Source Code Cross Referenced for Codegen.java in  » Scripting » rhino » org » mozilla » javascript » optimizer » Java Source Code / Java DocumentationJava Source Code and Java Documentation

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


0001:        /* ***** BEGIN LICENSE BLOCK *****
0002:         * Version: MPL 1.1/GPL 2.0
0003:         *
0004:         * The contents of this file are subject to the Mozilla Public License Version
0005:         * 1.1 (the "License"); you may not use this file except in compliance with
0006:         * the License. You may obtain a copy of the License at
0007:         * http://www.mozilla.org/MPL/
0008:         *
0009:         * Software distributed under the License is distributed on an "AS IS" basis,
0010:         * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
0011:         * for the specific language governing rights and limitations under the
0012:         * License.
0013:         *
0014:         * The Original Code is Rhino code, released
0015:         * May 6, 1999.
0016:         *
0017:         * The Initial Developer of the Original Code is
0018:         * Netscape Communications Corporation.
0019:         * Portions created by the Initial Developer are Copyright (C) 1997-2000
0020:         * the Initial Developer. All Rights Reserved.
0021:         *
0022:         * Contributor(s):
0023:         *   Norris Boyd
0024:         *   Kemal Bayram
0025:         *   Igor Bukanov
0026:         *   Bob Jervis
0027:         *   Roger Lawrence
0028:         *   Andi Vajda
0029:         *   Hannes Wallnoefer
0030:         *
0031:         * Alternatively, the contents of this file may be used under the terms of
0032:         * the GNU General Public License Version 2 or later (the "GPL"), in which
0033:         * case the provisions of the GPL are applicable instead of those above. If
0034:         * you wish to allow use of your version of this file only under the terms of
0035:         * the GPL and not to allow others to use your version of this file under the
0036:         * MPL, indicate your decision by deleting the provisions above and replacing
0037:         * them with the notice and other provisions required by the GPL. If you do
0038:         * not delete the provisions above, a recipient may use your version of this
0039:         * file under either the MPL or the GPL.
0040:         *
0041:         * ***** END LICENSE BLOCK ***** */
0042:
0043:        package org.mozilla.javascript.optimizer;
0044:
0045:        import org.mozilla.javascript.*;
0046:        import org.mozilla.classfile.*;
0047:        import java.util.*;
0048:        import java.lang.reflect.Constructor;
0049:        import java.util.Hashtable;
0050:
0051:        /**
0052:         * This class generates code for a given IR tree.
0053:         *
0054:         * @author Norris Boyd
0055:         * @author Roger Lawrence
0056:         */
0057:
0058:        public class Codegen implements  Evaluator {
0059:            public void captureStackInfo(RhinoException ex) {
0060:                throw new UnsupportedOperationException();
0061:            }
0062:
0063:            public String getSourcePositionFromStack(Context cx, int[] linep) {
0064:                throw new UnsupportedOperationException();
0065:            }
0066:
0067:            public String getPatchedStack(RhinoException ex,
0068:                    String nativeStackTrace) {
0069:                throw new UnsupportedOperationException();
0070:            }
0071:
0072:            public List getScriptStack(RhinoException ex) {
0073:                throw new UnsupportedOperationException();
0074:            }
0075:
0076:            public void setEvalScriptFlag(Script script) {
0077:                throw new UnsupportedOperationException();
0078:            }
0079:
0080:            public Object compile(CompilerEnvirons compilerEnv,
0081:                    ScriptOrFnNode tree, String encodedSource,
0082:                    boolean returnFunction) {
0083:                int serial;
0084:                synchronized (globalLock) {
0085:                    serial = ++globalSerialClassCounter;
0086:                }
0087:                String mainClassName = "org.mozilla.javascript.gen.c" + serial;
0088:
0089:                byte[] mainClassBytes = compileToClassFile(compilerEnv,
0090:                        mainClassName, tree, encodedSource, returnFunction);
0091:
0092:                return new Object[] { mainClassName, mainClassBytes };
0093:            }
0094:
0095:            public Script createScriptObject(Object bytecode,
0096:                    Object staticSecurityDomain) {
0097:                Class cl = defineClass(bytecode, staticSecurityDomain);
0098:
0099:                Script script;
0100:                try {
0101:                    script = (Script) cl.newInstance();
0102:                } catch (Exception ex) {
0103:                    throw new RuntimeException(
0104:                            "Unable to instantiate compiled class:"
0105:                                    + ex.toString());
0106:                }
0107:                return script;
0108:            }
0109:
0110:            public Function createFunctionObject(Context cx, Scriptable scope,
0111:                    Object bytecode, Object staticSecurityDomain) {
0112:                Class cl = defineClass(bytecode, staticSecurityDomain);
0113:
0114:                NativeFunction f;
0115:                try {
0116:                    Constructor ctor = cl.getConstructors()[0];
0117:                    Object[] initArgs = { scope, cx, new Integer(0) };
0118:                    f = (NativeFunction) ctor.newInstance(initArgs);
0119:                } catch (Exception ex) {
0120:                    throw new RuntimeException(
0121:                            "Unable to instantiate compiled class:"
0122:                                    + ex.toString());
0123:                }
0124:                return f;
0125:            }
0126:
0127:            private Class defineClass(Object bytecode,
0128:                    Object staticSecurityDomain) {
0129:                Object[] nameBytesPair = (Object[]) bytecode;
0130:                String className = (String) nameBytesPair[0];
0131:                byte[] classBytes = (byte[]) nameBytesPair[1];
0132:
0133:                // The generated classes in this case refer only to Rhino classes
0134:                // which must be accessible through this class loader
0135:                ClassLoader rhinoLoader = getClass().getClassLoader();
0136:                GeneratedClassLoader loader;
0137:                loader = SecurityController.createLoader(rhinoLoader,
0138:                        staticSecurityDomain);
0139:                Exception e;
0140:                try {
0141:                    Class cl = loader.defineClass(className, classBytes);
0142:                    loader.linkClass(cl);
0143:                    return cl;
0144:                } catch (SecurityException x) {
0145:                    e = x;
0146:                } catch (IllegalArgumentException x) {
0147:                    e = x;
0148:                }
0149:                throw new RuntimeException("Malformed optimizer package " + e);
0150:            }
0151:
0152:            byte[] compileToClassFile(CompilerEnvirons compilerEnv,
0153:                    String mainClassName, ScriptOrFnNode scriptOrFn,
0154:                    String encodedSource, boolean returnFunction) {
0155:                this .compilerEnv = compilerEnv;
0156:
0157:                transform(scriptOrFn);
0158:
0159:                if (Token.printTrees) {
0160:                    System.out.println(scriptOrFn.toStringTree(scriptOrFn));
0161:                }
0162:
0163:                if (returnFunction) {
0164:                    scriptOrFn = scriptOrFn.getFunctionNode(0);
0165:                }
0166:
0167:                initScriptOrFnNodesData(scriptOrFn);
0168:
0169:                this .mainClassName = mainClassName;
0170:                this .mainClassSignature = ClassFileWriter
0171:                        .classNameToSignature(mainClassName);
0172:
0173:                try {
0174:                    return generateCode(encodedSource);
0175:                } catch (ClassFileWriter.ClassFileFormatException e) {
0176:                    throw reportClassFileFormatException(scriptOrFn, e
0177:                            .getMessage());
0178:                }
0179:            }
0180:
0181:            private RuntimeException reportClassFileFormatException(
0182:                    ScriptOrFnNode scriptOrFn, String message) {
0183:                String msg = scriptOrFn instanceof  FunctionNode ? ScriptRuntime
0184:                        .getMessage2("msg.while.compiling.fn",
0185:                                ((FunctionNode) scriptOrFn).getFunctionName(),
0186:                                message) : ScriptRuntime.getMessage1(
0187:                        "msg.while.compiling.script", message);
0188:                return Context.reportRuntimeError(msg, scriptOrFn
0189:                        .getSourceName(), scriptOrFn.getLineno(), null, 0);
0190:            }
0191:
0192:            private void transform(ScriptOrFnNode tree) {
0193:                initOptFunctions_r(tree);
0194:
0195:                int optLevel = compilerEnv.getOptimizationLevel();
0196:
0197:                Hashtable possibleDirectCalls = null;
0198:                if (optLevel > 0) {
0199:                    /*
0200:                     * Collect all of the contained functions into a hashtable
0201:                     * so that the call optimizer can access the class name & parameter
0202:                     * count for any call it encounters
0203:                     */
0204:                    if (tree.getType() == Token.SCRIPT) {
0205:                        int functionCount = tree.getFunctionCount();
0206:                        for (int i = 0; i != functionCount; ++i) {
0207:                            OptFunctionNode ofn = OptFunctionNode.get(tree, i);
0208:                            if (ofn.fnode.getFunctionType() == FunctionNode.FUNCTION_STATEMENT) {
0209:                                String name = ofn.fnode.getFunctionName();
0210:                                if (name.length() != 0) {
0211:                                    if (possibleDirectCalls == null) {
0212:                                        possibleDirectCalls = new Hashtable();
0213:                                    }
0214:                                    possibleDirectCalls.put(name, ofn);
0215:                                }
0216:                            }
0217:                        }
0218:                    }
0219:                }
0220:
0221:                if (possibleDirectCalls != null) {
0222:                    directCallTargets = new ObjArray();
0223:                }
0224:
0225:                OptTransformer ot = new OptTransformer(possibleDirectCalls,
0226:                        directCallTargets);
0227:                ot.transform(tree);
0228:
0229:                if (optLevel > 0) {
0230:                    (new Optimizer()).optimize(tree);
0231:                }
0232:            }
0233:
0234:            private static void initOptFunctions_r(ScriptOrFnNode scriptOrFn) {
0235:                for (int i = 0, N = scriptOrFn.getFunctionCount(); i != N; ++i) {
0236:                    FunctionNode fn = scriptOrFn.getFunctionNode(i);
0237:                    new OptFunctionNode(fn);
0238:                    initOptFunctions_r(fn);
0239:                }
0240:            }
0241:
0242:            private void initScriptOrFnNodesData(ScriptOrFnNode scriptOrFn) {
0243:                ObjArray x = new ObjArray();
0244:                collectScriptOrFnNodes_r(scriptOrFn, x);
0245:
0246:                int count = x.size();
0247:                scriptOrFnNodes = new ScriptOrFnNode[count];
0248:                x.toArray(scriptOrFnNodes);
0249:
0250:                scriptOrFnIndexes = new ObjToIntMap(count);
0251:                for (int i = 0; i != count; ++i) {
0252:                    scriptOrFnIndexes.put(scriptOrFnNodes[i], i);
0253:                }
0254:            }
0255:
0256:            private static void collectScriptOrFnNodes_r(ScriptOrFnNode n,
0257:                    ObjArray x) {
0258:                x.add(n);
0259:                int nestedCount = n.getFunctionCount();
0260:                for (int i = 0; i != nestedCount; ++i) {
0261:                    collectScriptOrFnNodes_r(n.getFunctionNode(i), x);
0262:                }
0263:            }
0264:
0265:            private byte[] generateCode(String encodedSource) {
0266:                boolean hasScript = (scriptOrFnNodes[0].getType() == Token.SCRIPT);
0267:                boolean hasFunctions = (scriptOrFnNodes.length > 1 || !hasScript);
0268:
0269:                String sourceFile = null;
0270:                if (compilerEnv.isGenerateDebugInfo()) {
0271:                    sourceFile = scriptOrFnNodes[0].getSourceName();
0272:                }
0273:
0274:                ClassFileWriter cfw = new ClassFileWriter(mainClassName,
0275:                        SUPER_CLASS_NAME, sourceFile);
0276:                cfw.addField(ID_FIELD_NAME, "I", ClassFileWriter.ACC_PRIVATE);
0277:                cfw.addField(DIRECT_CALL_PARENT_FIELD, mainClassSignature,
0278:                        ClassFileWriter.ACC_PRIVATE);
0279:                cfw.addField(REGEXP_ARRAY_FIELD_NAME, REGEXP_ARRAY_FIELD_TYPE,
0280:                        ClassFileWriter.ACC_PRIVATE);
0281:
0282:                if (hasFunctions) {
0283:                    generateFunctionConstructor(cfw);
0284:                }
0285:
0286:                if (hasScript) {
0287:                    cfw.addInterface("org/mozilla/javascript/Script");
0288:                    generateScriptCtor(cfw);
0289:                    generateMain(cfw);
0290:                    generateExecute(cfw);
0291:                }
0292:
0293:                generateCallMethod(cfw);
0294:                generateResumeGenerator(cfw);
0295:
0296:                generateNativeFunctionOverrides(cfw, encodedSource);
0297:
0298:                int count = scriptOrFnNodes.length;
0299:                for (int i = 0; i != count; ++i) {
0300:                    ScriptOrFnNode n = scriptOrFnNodes[i];
0301:
0302:                    BodyCodegen bodygen = new BodyCodegen();
0303:                    bodygen.cfw = cfw;
0304:                    bodygen.codegen = this ;
0305:                    bodygen.compilerEnv = compilerEnv;
0306:                    bodygen.scriptOrFn = n;
0307:                    bodygen.scriptOrFnIndex = i;
0308:
0309:                    try {
0310:                        bodygen.generateBodyCode();
0311:                    } catch (ClassFileWriter.ClassFileFormatException e) {
0312:                        throw reportClassFileFormatException(n, e.getMessage());
0313:                    }
0314:
0315:                    if (n.getType() == Token.FUNCTION) {
0316:                        OptFunctionNode ofn = OptFunctionNode.get(n);
0317:                        generateFunctionInit(cfw, ofn);
0318:                        if (ofn.isTargetOfDirectCall()) {
0319:                            emitDirectConstructor(cfw, ofn);
0320:                        }
0321:                    }
0322:                }
0323:
0324:                if (directCallTargets != null) {
0325:                    int N = directCallTargets.size();
0326:                    for (int j = 0; j != N; ++j) {
0327:                        cfw
0328:                                .addField(getDirectTargetFieldName(j),
0329:                                        mainClassSignature,
0330:                                        ClassFileWriter.ACC_PRIVATE);
0331:                    }
0332:                }
0333:
0334:                emitRegExpInit(cfw);
0335:                emitConstantDudeInitializers(cfw);
0336:
0337:                return cfw.toByteArray();
0338:            }
0339:
0340:            private void emitDirectConstructor(ClassFileWriter cfw,
0341:                    OptFunctionNode ofn) {
0342:                /*
0343:                 we generate ..
0344:                 Scriptable directConstruct(<directCallArgs>) {
0345:                 Scriptable newInstance = createObject(cx, scope);
0346:                 Object val = <body-name>(cx, scope, newInstance, <directCallArgs>);
0347:                 if (val instanceof Scriptable) {
0348:                 return (Scriptable) val;
0349:                 }
0350:                 return newInstance;
0351:                 }
0352:                 */
0353:                cfw
0354:                        .startMethod(
0355:                                getDirectCtorName(ofn.fnode),
0356:                                getBodyMethodSignature(ofn.fnode),
0357:                                (short) (ClassFileWriter.ACC_STATIC | ClassFileWriter.ACC_PRIVATE));
0358:
0359:                int argCount = ofn.fnode.getParamCount();
0360:                int firstLocal = (4 + argCount * 3) + 1;
0361:
0362:                cfw.addALoad(0); // this
0363:                cfw.addALoad(1); // cx
0364:                cfw.addALoad(2); // scope
0365:                cfw.addInvoke(ByteCode.INVOKEVIRTUAL,
0366:                        "org/mozilla/javascript/BaseFunction", "createObject",
0367:                        "(Lorg/mozilla/javascript/Context;"
0368:                                + "Lorg/mozilla/javascript/Scriptable;"
0369:                                + ")Lorg/mozilla/javascript/Scriptable;");
0370:                cfw.addAStore(firstLocal);
0371:
0372:                cfw.addALoad(0);
0373:                cfw.addALoad(1);
0374:                cfw.addALoad(2);
0375:                cfw.addALoad(firstLocal);
0376:                for (int i = 0; i < argCount; i++) {
0377:                    cfw.addALoad(4 + (i * 3));
0378:                    cfw.addDLoad(5 + (i * 3));
0379:                }
0380:                cfw.addALoad(4 + argCount * 3);
0381:                cfw.addInvoke(ByteCode.INVOKESTATIC, mainClassName,
0382:                        getBodyMethodName(ofn.fnode),
0383:                        getBodyMethodSignature(ofn.fnode));
0384:                int exitLabel = cfw.acquireLabel();
0385:                cfw.add(ByteCode.DUP); // make a copy of direct call result
0386:                cfw.add(ByteCode.INSTANCEOF,
0387:                        "org/mozilla/javascript/Scriptable");
0388:                cfw.add(ByteCode.IFEQ, exitLabel);
0389:                // cast direct call result
0390:                cfw
0391:                        .add(ByteCode.CHECKCAST,
0392:                                "org/mozilla/javascript/Scriptable");
0393:                cfw.add(ByteCode.ARETURN);
0394:                cfw.markLabel(exitLabel);
0395:
0396:                cfw.addALoad(firstLocal);
0397:                cfw.add(ByteCode.ARETURN);
0398:
0399:                cfw.stopMethod((short) (firstLocal + 1));
0400:            }
0401:
0402:            static boolean isGenerator(ScriptOrFnNode node) {
0403:                return (node.getType() == Token.FUNCTION)
0404:                        && ((FunctionNode) node).isGenerator();
0405:            }
0406:
0407:            // How dispatch to generators works:
0408:            // Two methods are generated corresponding to a user-written generator.
0409:            // One of these creates a generator object (NativeGenerator), which is
0410:            // returned to the user. The other method contains all of the body code
0411:            // of the generator.
0412:            // When a user calls a generator, the call() method dispatches control to
0413:            // to the method that creates the NativeGenerator object. Subsequently when
0414:            // the user invokes .next(), .send() or any such method on the generator
0415:            // object, the resumeGenerator() below dispatches the call to the
0416:            // method corresponding to the generator body. As a matter of convention
0417:            // the generator body is given the name of the generator activation function
0418:            // appended by "_gen".
0419:            private void generateResumeGenerator(ClassFileWriter cfw) {
0420:                boolean hasGenerators = false;
0421:                for (int i = 0; i < scriptOrFnNodes.length; i++) {
0422:                    if (isGenerator(scriptOrFnNodes[i]))
0423:                        hasGenerators = true;
0424:                }
0425:
0426:                // if there are no generators defined, we don't implement a
0427:                // resumeGenerator(). The base class provides a default implementation. 
0428:                if (!hasGenerators)
0429:                    return;
0430:
0431:                cfw
0432:                        .startMethod(
0433:                                "resumeGenerator",
0434:                                "(Lorg/mozilla/javascript/Context;"
0435:                                        + "Lorg/mozilla/javascript/Scriptable;"
0436:                                        + "ILjava/lang/Object;"
0437:                                        + "Ljava/lang/Object;)Ljava/lang/Object;",
0438:                                (short) (ClassFileWriter.ACC_PUBLIC | ClassFileWriter.ACC_FINAL));
0439:
0440:                // load arguments for dispatch to the corresponding *_gen method 
0441:                cfw.addALoad(0);
0442:                cfw.addALoad(1);
0443:                cfw.addALoad(2);
0444:                cfw.addALoad(4);
0445:                cfw.addALoad(5);
0446:                cfw.addILoad(3);
0447:
0448:                cfw.addLoadThis();
0449:                cfw.add(ByteCode.GETFIELD, cfw.getClassName(), ID_FIELD_NAME,
0450:                        "I");
0451:
0452:                int startSwitch = cfw.addTableSwitch(0,
0453:                        scriptOrFnNodes.length - 1);
0454:                cfw.markTableSwitchDefault(startSwitch);
0455:                int endlabel = cfw.acquireLabel();
0456:
0457:                for (int i = 0; i < scriptOrFnNodes.length; i++) {
0458:                    ScriptOrFnNode n = scriptOrFnNodes[i];
0459:                    cfw.markTableSwitchCase(startSwitch, i, (short) 6);
0460:                    if (isGenerator(n)) {
0461:                        String type = "(" + mainClassSignature
0462:                                + "Lorg/mozilla/javascript/Context;"
0463:                                + "Lorg/mozilla/javascript/Scriptable;"
0464:                                + "Ljava/lang/Object;"
0465:                                + "Ljava/lang/Object;I)Ljava/lang/Object;";
0466:                        cfw.addInvoke(ByteCode.INVOKESTATIC, mainClassName,
0467:                                getBodyMethodName(n) + "_gen", type);
0468:                        cfw.add(ByteCode.ARETURN);
0469:                    } else {
0470:                        cfw.add(ByteCode.GOTO, endlabel);
0471:                    }
0472:                }
0473:
0474:                cfw.markLabel(endlabel);
0475:                pushUndefined(cfw);
0476:                cfw.add(ByteCode.ARETURN);
0477:
0478:                // this method uses as many locals as there are arguments (hence 6)
0479:                cfw.stopMethod((short) 6);
0480:            }
0481:
0482:            private void generateCallMethod(ClassFileWriter cfw) {
0483:                cfw
0484:                        .startMethod(
0485:                                "call",
0486:                                "(Lorg/mozilla/javascript/Context;"
0487:                                        + "Lorg/mozilla/javascript/Scriptable;"
0488:                                        + "Lorg/mozilla/javascript/Scriptable;"
0489:                                        + "[Ljava/lang/Object;)Ljava/lang/Object;",
0490:                                (short) (ClassFileWriter.ACC_PUBLIC | ClassFileWriter.ACC_FINAL));
0491:
0492:                // Generate code for:
0493:                // if (!ScriptRuntime.hasTopCall(cx)) {
0494:                //     return ScriptRuntime.doTopCall(this, cx, scope, thisObj, args);
0495:                // }
0496:
0497:                int nonTopCallLabel = cfw.acquireLabel();
0498:                cfw.addALoad(1); //cx
0499:                cfw.addInvoke(ByteCode.INVOKESTATIC,
0500:                        "org/mozilla/javascript/ScriptRuntime", "hasTopCall",
0501:                        "(Lorg/mozilla/javascript/Context;" + ")Z");
0502:                cfw.add(ByteCode.IFNE, nonTopCallLabel);
0503:                cfw.addALoad(0);
0504:                cfw.addALoad(1);
0505:                cfw.addALoad(2);
0506:                cfw.addALoad(3);
0507:                cfw.addALoad(4);
0508:                cfw
0509:                        .addInvoke(ByteCode.INVOKESTATIC,
0510:                                "org/mozilla/javascript/ScriptRuntime",
0511:                                "doTopCall",
0512:                                "(Lorg/mozilla/javascript/Callable;"
0513:                                        + "Lorg/mozilla/javascript/Context;"
0514:                                        + "Lorg/mozilla/javascript/Scriptable;"
0515:                                        + "Lorg/mozilla/javascript/Scriptable;"
0516:                                        + "[Ljava/lang/Object;"
0517:                                        + ")Ljava/lang/Object;");
0518:                cfw.add(ByteCode.ARETURN);
0519:                cfw.markLabel(nonTopCallLabel);
0520:
0521:                // Now generate switch to call the real methods
0522:                cfw.addALoad(0);
0523:                cfw.addALoad(1);
0524:                cfw.addALoad(2);
0525:                cfw.addALoad(3);
0526:                cfw.addALoad(4);
0527:
0528:                int end = scriptOrFnNodes.length;
0529:                boolean generateSwitch = (2 <= end);
0530:
0531:                int switchStart = 0;
0532:                int switchStackTop = 0;
0533:                if (generateSwitch) {
0534:                    cfw.addLoadThis();
0535:                    cfw.add(ByteCode.GETFIELD, cfw.getClassName(),
0536:                            ID_FIELD_NAME, "I");
0537:                    // do switch from (1,  end - 1) mapping 0 to
0538:                    // the default case
0539:                    switchStart = cfw.addTableSwitch(1, end - 1);
0540:                }
0541:
0542:                for (int i = 0; i != end; ++i) {
0543:                    ScriptOrFnNode n = scriptOrFnNodes[i];
0544:                    if (generateSwitch) {
0545:                        if (i == 0) {
0546:                            cfw.markTableSwitchDefault(switchStart);
0547:                            switchStackTop = cfw.getStackTop();
0548:                        } else {
0549:                            cfw.markTableSwitchCase(switchStart, i - 1,
0550:                                    switchStackTop);
0551:                        }
0552:                    }
0553:                    if (n.getType() == Token.FUNCTION) {
0554:                        OptFunctionNode ofn = OptFunctionNode.get(n);
0555:                        if (ofn.isTargetOfDirectCall()) {
0556:                            int pcount = ofn.fnode.getParamCount();
0557:                            if (pcount != 0) {
0558:                                // loop invariant:
0559:                                // stack top == arguments array from addALoad4()
0560:                                for (int p = 0; p != pcount; ++p) {
0561:                                    cfw.add(ByteCode.ARRAYLENGTH);
0562:                                    cfw.addPush(p);
0563:                                    int undefArg = cfw.acquireLabel();
0564:                                    int beyond = cfw.acquireLabel();
0565:                                    cfw.add(ByteCode.IF_ICMPLE, undefArg);
0566:                                    // get array[p]
0567:                                    cfw.addALoad(4);
0568:                                    cfw.addPush(p);
0569:                                    cfw.add(ByteCode.AALOAD);
0570:                                    cfw.add(ByteCode.GOTO, beyond);
0571:                                    cfw.markLabel(undefArg);
0572:                                    pushUndefined(cfw);
0573:                                    cfw.markLabel(beyond);
0574:                                    // Only one push
0575:                                    cfw.adjustStackTop(-1);
0576:                                    cfw.addPush(0.0);
0577:                                    // restore invariant
0578:                                    cfw.addALoad(4);
0579:                                }
0580:                            }
0581:                        }
0582:                    }
0583:                    cfw.addInvoke(ByteCode.INVOKESTATIC, mainClassName,
0584:                            getBodyMethodName(n), getBodyMethodSignature(n));
0585:                    cfw.add(ByteCode.ARETURN);
0586:                }
0587:                cfw.stopMethod((short) 5);
0588:                // 5: this, cx, scope, js this, args[]
0589:            }
0590:
0591:            private void generateMain(ClassFileWriter cfw) {
0592:                cfw
0593:                        .startMethod(
0594:                                "main",
0595:                                "([Ljava/lang/String;)V",
0596:                                (short) (ClassFileWriter.ACC_PUBLIC | ClassFileWriter.ACC_STATIC));
0597:
0598:                // load new ScriptImpl()
0599:                cfw.add(ByteCode.NEW, cfw.getClassName());
0600:                cfw.add(ByteCode.DUP);
0601:                cfw.addInvoke(ByteCode.INVOKESPECIAL, cfw.getClassName(),
0602:                        "<init>", "()V");
0603:                // load 'args'
0604:                cfw.add(ByteCode.ALOAD_0);
0605:                // Call mainMethodClass.main(Script script, String[] args)
0606:                cfw
0607:                        .addInvoke(ByteCode.INVOKESTATIC, mainMethodClass,
0608:                                "main",
0609:                                "(Lorg/mozilla/javascript/Script;[Ljava/lang/String;)V");
0610:                cfw.add(ByteCode.RETURN);
0611:                // 1 = String[] args
0612:                cfw.stopMethod((short) 1);
0613:            }
0614:
0615:            private void generateExecute(ClassFileWriter cfw) {
0616:                cfw
0617:                        .startMethod(
0618:                                "exec",
0619:                                "(Lorg/mozilla/javascript/Context;"
0620:                                        + "Lorg/mozilla/javascript/Scriptable;"
0621:                                        + ")Ljava/lang/Object;",
0622:                                (short) (ClassFileWriter.ACC_PUBLIC | ClassFileWriter.ACC_FINAL));
0623:
0624:                final int CONTEXT_ARG = 1;
0625:                final int SCOPE_ARG = 2;
0626:
0627:                cfw.addLoadThis();
0628:                cfw.addALoad(CONTEXT_ARG);
0629:                cfw.addALoad(SCOPE_ARG);
0630:                cfw.add(ByteCode.DUP);
0631:                cfw.add(ByteCode.ACONST_NULL);
0632:                cfw
0633:                        .addInvoke(ByteCode.INVOKEVIRTUAL, cfw.getClassName(),
0634:                                "call", "(Lorg/mozilla/javascript/Context;"
0635:                                        + "Lorg/mozilla/javascript/Scriptable;"
0636:                                        + "Lorg/mozilla/javascript/Scriptable;"
0637:                                        + "[Ljava/lang/Object;"
0638:                                        + ")Ljava/lang/Object;");
0639:
0640:                cfw.add(ByteCode.ARETURN);
0641:                // 3 = this + context + scope
0642:                cfw.stopMethod((short) 3);
0643:            }
0644:
0645:            private void generateScriptCtor(ClassFileWriter cfw) {
0646:                cfw.startMethod("<init>", "()V", ClassFileWriter.ACC_PUBLIC);
0647:
0648:                cfw.addLoadThis();
0649:                cfw.addInvoke(ByteCode.INVOKESPECIAL, SUPER_CLASS_NAME,
0650:                        "<init>", "()V");
0651:                // set id to 0
0652:                cfw.addLoadThis();
0653:                cfw.addPush(0);
0654:                cfw.add(ByteCode.PUTFIELD, cfw.getClassName(), ID_FIELD_NAME,
0655:                        "I");
0656:
0657:                cfw.add(ByteCode.RETURN);
0658:                // 1 parameter = this
0659:                cfw.stopMethod((short) 1);
0660:            }
0661:
0662:            private void generateFunctionConstructor(ClassFileWriter cfw) {
0663:                final int SCOPE_ARG = 1;
0664:                final int CONTEXT_ARG = 2;
0665:                final int ID_ARG = 3;
0666:
0667:                cfw.startMethod("<init>", FUNCTION_CONSTRUCTOR_SIGNATURE,
0668:                        ClassFileWriter.ACC_PUBLIC);
0669:                cfw.addALoad(0);
0670:                cfw.addInvoke(ByteCode.INVOKESPECIAL, SUPER_CLASS_NAME,
0671:                        "<init>", "()V");
0672:
0673:                cfw.addLoadThis();
0674:                cfw.addILoad(ID_ARG);
0675:                cfw.add(ByteCode.PUTFIELD, cfw.getClassName(), ID_FIELD_NAME,
0676:                        "I");
0677:
0678:                cfw.addLoadThis();
0679:                cfw.addALoad(CONTEXT_ARG);
0680:                cfw.addALoad(SCOPE_ARG);
0681:
0682:                int start = (scriptOrFnNodes[0].getType() == Token.SCRIPT) ? 1
0683:                        : 0;
0684:                int end = scriptOrFnNodes.length;
0685:                if (start == end)
0686:                    throw badTree();
0687:                boolean generateSwitch = (2 <= end - start);
0688:
0689:                int switchStart = 0;
0690:                int switchStackTop = 0;
0691:                if (generateSwitch) {
0692:                    cfw.addILoad(ID_ARG);
0693:                    // do switch from (start + 1,  end - 1) mapping start to
0694:                    // the default case
0695:                    switchStart = cfw.addTableSwitch(start + 1, end - 1);
0696:                }
0697:
0698:                for (int i = start; i != end; ++i) {
0699:                    if (generateSwitch) {
0700:                        if (i == start) {
0701:                            cfw.markTableSwitchDefault(switchStart);
0702:                            switchStackTop = cfw.getStackTop();
0703:                        } else {
0704:                            cfw.markTableSwitchCase(switchStart, i - 1 - start,
0705:                                    switchStackTop);
0706:                        }
0707:                    }
0708:                    OptFunctionNode ofn = OptFunctionNode
0709:                            .get(scriptOrFnNodes[i]);
0710:                    cfw.addInvoke(ByteCode.INVOKEVIRTUAL, mainClassName,
0711:                            getFunctionInitMethodName(ofn),
0712:                            FUNCTION_INIT_SIGNATURE);
0713:                    cfw.add(ByteCode.RETURN);
0714:                }
0715:
0716:                // 4 = this + scope + context + id
0717:                cfw.stopMethod((short) 4);
0718:            }
0719:
0720:            private void generateFunctionInit(ClassFileWriter cfw,
0721:                    OptFunctionNode ofn) {
0722:                final int CONTEXT_ARG = 1;
0723:                final int SCOPE_ARG = 2;
0724:                cfw
0725:                        .startMethod(
0726:                                getFunctionInitMethodName(ofn),
0727:                                FUNCTION_INIT_SIGNATURE,
0728:                                (short) (ClassFileWriter.ACC_PRIVATE | ClassFileWriter.ACC_FINAL));
0729:
0730:                // Call NativeFunction.initScriptFunction
0731:                cfw.addLoadThis();
0732:                cfw.addALoad(CONTEXT_ARG);
0733:                cfw.addALoad(SCOPE_ARG);
0734:                cfw.addInvoke(ByteCode.INVOKEVIRTUAL,
0735:                        "org/mozilla/javascript/NativeFunction",
0736:                        "initScriptFunction",
0737:                        "(Lorg/mozilla/javascript/Context;"
0738:                                + "Lorg/mozilla/javascript/Scriptable;" + ")V");
0739:
0740:                // precompile all regexp literals
0741:                int regexpCount = ofn.fnode.getRegexpCount();
0742:                if (regexpCount != 0) {
0743:                    cfw.addLoadThis();
0744:                    pushRegExpArray(cfw, ofn.fnode, CONTEXT_ARG, SCOPE_ARG);
0745:                    cfw.add(ByteCode.PUTFIELD, mainClassName,
0746:                            REGEXP_ARRAY_FIELD_NAME, REGEXP_ARRAY_FIELD_TYPE);
0747:                }
0748:
0749:                cfw.add(ByteCode.RETURN);
0750:                // 3 = (scriptThis/functionRef) + scope + context
0751:                cfw.stopMethod((short) 3);
0752:            }
0753:
0754:            private void generateNativeFunctionOverrides(ClassFileWriter cfw,
0755:                    String encodedSource) {
0756:                // Override NativeFunction.getLanguageVersion() with
0757:                // public int getLanguageVersion() { return <version-constant>; }
0758:
0759:                cfw.startMethod("getLanguageVersion", "()I",
0760:                        ClassFileWriter.ACC_PUBLIC);
0761:
0762:                cfw.addPush(compilerEnv.getLanguageVersion());
0763:                cfw.add(ByteCode.IRETURN);
0764:
0765:                // 1: this and no argument or locals
0766:                cfw.stopMethod((short) 1);
0767:
0768:                // The rest of NativeFunction overrides require specific code for each
0769:                // script/function id
0770:
0771:                final int Do_getFunctionName = 0;
0772:                final int Do_getParamCount = 1;
0773:                final int Do_getParamAndVarCount = 2;
0774:                final int Do_getParamOrVarName = 3;
0775:                final int Do_getEncodedSource = 4;
0776:                final int Do_getParamOrVarConst = 5;
0777:                final int SWITCH_COUNT = 6;
0778:
0779:                for (int methodIndex = 0; methodIndex != SWITCH_COUNT; ++methodIndex) {
0780:                    if (methodIndex == Do_getEncodedSource
0781:                            && encodedSource == null) {
0782:                        continue;
0783:                    }
0784:
0785:                    // Generate:
0786:                    //   prologue;
0787:                    //   switch over function id to implement function-specific action
0788:                    //   epilogue
0789:
0790:                    short methodLocals;
0791:                    switch (methodIndex) {
0792:                    case Do_getFunctionName:
0793:                        methodLocals = 1; // Only this
0794:                        cfw.startMethod("getFunctionName",
0795:                                "()Ljava/lang/String;",
0796:                                ClassFileWriter.ACC_PUBLIC);
0797:                        break;
0798:                    case Do_getParamCount:
0799:                        methodLocals = 1; // Only this
0800:                        cfw.startMethod("getParamCount", "()I",
0801:                                ClassFileWriter.ACC_PUBLIC);
0802:                        break;
0803:                    case Do_getParamAndVarCount:
0804:                        methodLocals = 1; // Only this
0805:                        cfw.startMethod("getParamAndVarCount", "()I",
0806:                                ClassFileWriter.ACC_PUBLIC);
0807:                        break;
0808:                    case Do_getParamOrVarName:
0809:                        methodLocals = 1 + 1; // this + paramOrVarIndex
0810:                        cfw.startMethod("getParamOrVarName",
0811:                                "(I)Ljava/lang/String;",
0812:                                ClassFileWriter.ACC_PUBLIC);
0813:                        break;
0814:                    case Do_getParamOrVarConst:
0815:                        methodLocals = 1 + 1 + 1; // this + paramOrVarName
0816:                        cfw.startMethod("getParamOrVarConst", "(I)Z",
0817:                                ClassFileWriter.ACC_PUBLIC);
0818:                        break;
0819:                    case Do_getEncodedSource:
0820:                        methodLocals = 1; // Only this
0821:                        cfw.startMethod("getEncodedSource",
0822:                                "()Ljava/lang/String;",
0823:                                ClassFileWriter.ACC_PUBLIC);
0824:                        cfw.addPush(encodedSource);
0825:                        break;
0826:                    default:
0827:                        throw Kit.codeBug();
0828:                    }
0829:
0830:                    int count = scriptOrFnNodes.length;
0831:
0832:                    int switchStart = 0;
0833:                    int switchStackTop = 0;
0834:                    if (count > 1) {
0835:                        // Generate switch but only if there is more then one
0836:                        // script/function
0837:                        cfw.addLoadThis();
0838:                        cfw.add(ByteCode.GETFIELD, cfw.getClassName(),
0839:                                ID_FIELD_NAME, "I");
0840:
0841:                        // do switch from 1 .. count - 1 mapping 0 to the default case
0842:                        switchStart = cfw.addTableSwitch(1, count - 1);
0843:                    }
0844:
0845:                    for (int i = 0; i != count; ++i) {
0846:                        ScriptOrFnNode n = scriptOrFnNodes[i];
0847:                        if (i == 0) {
0848:                            if (count > 1) {
0849:                                cfw.markTableSwitchDefault(switchStart);
0850:                                switchStackTop = cfw.getStackTop();
0851:                            }
0852:                        } else {
0853:                            cfw.markTableSwitchCase(switchStart, i - 1,
0854:                                    switchStackTop);
0855:                        }
0856:
0857:                        // Impelemnet method-specific switch code
0858:                        switch (methodIndex) {
0859:                        case Do_getFunctionName:
0860:                            // Push function name
0861:                            if (n.getType() == Token.SCRIPT) {
0862:                                cfw.addPush("");
0863:                            } else {
0864:                                String name = ((FunctionNode) n)
0865:                                        .getFunctionName();
0866:                                cfw.addPush(name);
0867:                            }
0868:                            cfw.add(ByteCode.ARETURN);
0869:                            break;
0870:
0871:                        case Do_getParamCount:
0872:                            // Push number of defined parameters
0873:                            cfw.addPush(n.getParamCount());
0874:                            cfw.add(ByteCode.IRETURN);
0875:                            break;
0876:
0877:                        case Do_getParamAndVarCount:
0878:                            // Push number of defined parameters and declared variables
0879:                            cfw.addPush(n.getParamAndVarCount());
0880:                            cfw.add(ByteCode.IRETURN);
0881:                            break;
0882:
0883:                        case Do_getParamOrVarName:
0884:                            // Push name of parameter using another switch
0885:                            // over paramAndVarCount
0886:                            int paramAndVarCount = n.getParamAndVarCount();
0887:                            if (paramAndVarCount == 0) {
0888:                                // The runtime should never call the method in this
0889:                                // case but to make bytecode verifier happy return null
0890:                                // as throwing execption takes more code
0891:                                cfw.add(ByteCode.ACONST_NULL);
0892:                                cfw.add(ByteCode.ARETURN);
0893:                            } else if (paramAndVarCount == 1) {
0894:                                // As above do not check for valid index but always
0895:                                // return the name of the first param
0896:                                cfw.addPush(n.getParamOrVarName(0));
0897:                                cfw.add(ByteCode.ARETURN);
0898:                            } else {
0899:                                // Do switch over getParamOrVarName
0900:                                cfw.addILoad(1); // param or var index
0901:                                // do switch from 1 .. paramAndVarCount - 1 mapping 0
0902:                                // to the default case
0903:                                int paramSwitchStart = cfw.addTableSwitch(1,
0904:                                        paramAndVarCount - 1);
0905:                                for (int j = 0; j != paramAndVarCount; ++j) {
0906:                                    if (cfw.getStackTop() != 0)
0907:                                        Kit.codeBug();
0908:                                    String s = n.getParamOrVarName(j);
0909:                                    if (j == 0) {
0910:                                        cfw
0911:                                                .markTableSwitchDefault(paramSwitchStart);
0912:                                    } else {
0913:                                        cfw.markTableSwitchCase(
0914:                                                paramSwitchStart, j - 1, 0);
0915:                                    }
0916:                                    cfw.addPush(s);
0917:                                    cfw.add(ByteCode.ARETURN);
0918:                                }
0919:                            }
0920:                            break;
0921:
0922:                        case Do_getParamOrVarConst:
0923:                            // Push name of parameter using another switch
0924:                            // over paramAndVarCount
0925:                            paramAndVarCount = n.getParamAndVarCount();
0926:                            boolean[] constness = n.getParamAndVarConst();
0927:                            if (paramAndVarCount == 0) {
0928:                                // The runtime should never call the method in this
0929:                                // case but to make bytecode verifier happy return null
0930:                                // as throwing execption takes more code
0931:                                cfw.add(ByteCode.ICONST_0);
0932:                                cfw.add(ByteCode.IRETURN);
0933:                            } else if (paramAndVarCount == 1) {
0934:                                // As above do not check for valid index but always
0935:                                // return the name of the first param
0936:                                cfw.addPush(constness[0]);
0937:                                cfw.add(ByteCode.IRETURN);
0938:                            } else {
0939:                                // Do switch over getParamOrVarName
0940:                                cfw.addILoad(1); // param or var index
0941:                                // do switch from 1 .. paramAndVarCount - 1 mapping 0
0942:                                // to the default case
0943:                                int paramSwitchStart = cfw.addTableSwitch(1,
0944:                                        paramAndVarCount - 1);
0945:                                for (int j = 0; j != paramAndVarCount; ++j) {
0946:                                    if (cfw.getStackTop() != 0)
0947:                                        Kit.codeBug();
0948:                                    if (j == 0) {
0949:                                        cfw
0950:                                                .markTableSwitchDefault(paramSwitchStart);
0951:                                    } else {
0952:                                        cfw.markTableSwitchCase(
0953:                                                paramSwitchStart, j - 1, 0);
0954:                                    }
0955:                                    cfw.addPush(constness[j]);
0956:                                    cfw.add(ByteCode.IRETURN);
0957:                                }
0958:                            }
0959:                            break;
0960:
0961:                        case Do_getEncodedSource:
0962:                            // Push number encoded source start and end
0963:                            // to prepare for encodedSource.substring(start, end)
0964:                            cfw.addPush(n.getEncodedSourceStart());
0965:                            cfw.addPush(n.getEncodedSourceEnd());
0966:                            cfw.addInvoke(ByteCode.INVOKEVIRTUAL,
0967:                                    "java/lang/String", "substring",
0968:                                    "(II)Ljava/lang/String;");
0969:                            cfw.add(ByteCode.ARETURN);
0970:                            break;
0971:
0972:                        default:
0973:                            throw Kit.codeBug();
0974:                        }
0975:                    }
0976:
0977:                    cfw.stopMethod(methodLocals);
0978:                }
0979:            }
0980:
0981:            private void emitRegExpInit(ClassFileWriter cfw) {
0982:                // precompile all regexp literals
0983:
0984:                int totalRegCount = 0;
0985:                for (int i = 0; i != scriptOrFnNodes.length; ++i) {
0986:                    totalRegCount += scriptOrFnNodes[i].getRegexpCount();
0987:                }
0988:                if (totalRegCount == 0) {
0989:                    return;
0990:                }
0991:
0992:                cfw
0993:                        .startMethod(
0994:                                REGEXP_INIT_METHOD_NAME,
0995:                                REGEXP_INIT_METHOD_SIGNATURE,
0996:                                (short) (ClassFileWriter.ACC_STATIC
0997:                                        | ClassFileWriter.ACC_PRIVATE | ClassFileWriter.ACC_SYNCHRONIZED));
0998:                cfw
0999:                        .addField(
1000:                                "_reInitDone",
1001:                                "Z",
1002:                                (short) (ClassFileWriter.ACC_STATIC | ClassFileWriter.ACC_PRIVATE));
1003:                cfw.add(ByteCode.GETSTATIC, mainClassName, "_reInitDone", "Z");
1004:                int doInit = cfw.acquireLabel();
1005:                cfw.add(ByteCode.IFEQ, doInit);
1006:                cfw.add(ByteCode.RETURN);
1007:                cfw.markLabel(doInit);
1008:
1009:                for (int i = 0; i != scriptOrFnNodes.length; ++i) {
1010:                    ScriptOrFnNode n = scriptOrFnNodes[i];
1011:                    int regCount = n.getRegexpCount();
1012:                    for (int j = 0; j != regCount; ++j) {
1013:                        String reFieldName = getCompiledRegexpName(n, j);
1014:                        String reFieldType = "Ljava/lang/Object;";
1015:                        String reString = n.getRegexpString(j);
1016:                        String reFlags = n.getRegexpFlags(j);
1017:                        cfw
1018:                                .addField(
1019:                                        reFieldName,
1020:                                        reFieldType,
1021:                                        (short) (ClassFileWriter.ACC_STATIC | ClassFileWriter.ACC_PRIVATE));
1022:                        cfw.addALoad(0); // proxy
1023:                        cfw.addALoad(1); // context
1024:                        cfw.addPush(reString);
1025:                        if (reFlags == null) {
1026:                            cfw.add(ByteCode.ACONST_NULL);
1027:                        } else {
1028:                            cfw.addPush(reFlags);
1029:                        }
1030:                        cfw
1031:                                .addInvoke(
1032:                                        ByteCode.INVOKEINTERFACE,
1033:                                        "org/mozilla/javascript/RegExpProxy",
1034:                                        "compileRegExp",
1035:                                        "(Lorg/mozilla/javascript/Context;"
1036:                                                + "Ljava/lang/String;Ljava/lang/String;"
1037:                                                + ")Ljava/lang/Object;");
1038:                        cfw.add(ByteCode.PUTSTATIC, mainClassName, reFieldName,
1039:                                reFieldType);
1040:                    }
1041:                }
1042:
1043:                cfw.addPush(1);
1044:                cfw.add(ByteCode.PUTSTATIC, mainClassName, "_reInitDone", "Z");
1045:                cfw.add(ByteCode.RETURN);
1046:                cfw.stopMethod((short) 2);
1047:            }
1048:
1049:            private void emitConstantDudeInitializers(ClassFileWriter cfw) {
1050:                int N = itsConstantListSize;
1051:                if (N == 0)
1052:                    return;
1053:
1054:                cfw
1055:                        .startMethod(
1056:                                "<clinit>",
1057:                                "()V",
1058:                                (short) (ClassFileWriter.ACC_STATIC | ClassFileWriter.ACC_FINAL));
1059:
1060:                double[] array = itsConstantList;
1061:                for (int i = 0; i != N; ++i) {
1062:                    double num = array[i];
1063:                    String constantName = "_k" + i;
1064:                    String constantType = getStaticConstantWrapperType(num);
1065:                    cfw
1066:                            .addField(
1067:                                    constantName,
1068:                                    constantType,
1069:                                    (short) (ClassFileWriter.ACC_STATIC | ClassFileWriter.ACC_PRIVATE));
1070:                    int inum = (int) num;
1071:                    if (inum == num) {
1072:                        cfw.add(ByteCode.NEW, "java/lang/Integer");
1073:                        cfw.add(ByteCode.DUP);
1074:                        cfw.addPush(inum);
1075:                        cfw.addInvoke(ByteCode.INVOKESPECIAL,
1076:                                "java/lang/Integer", "<init>", "(I)V");
1077:                    } else {
1078:                        cfw.addPush(num);
1079:                        addDoubleWrap(cfw);
1080:                    }
1081:                    cfw.add(ByteCode.PUTSTATIC, mainClassName, constantName,
1082:                            constantType);
1083:                }
1084:
1085:                cfw.add(ByteCode.RETURN);
1086:                cfw.stopMethod((short) 0);
1087:            }
1088:
1089:            void pushRegExpArray(ClassFileWriter cfw, ScriptOrFnNode n,
1090:                    int contextArg, int scopeArg) {
1091:                int regexpCount = n.getRegexpCount();
1092:                if (regexpCount == 0)
1093:                    throw badTree();
1094:
1095:                cfw.addPush(regexpCount);
1096:                cfw.add(ByteCode.ANEWARRAY, "java/lang/Object");
1097:
1098:                cfw.addALoad(contextArg);
1099:                cfw.addInvoke(ByteCode.INVOKESTATIC,
1100:                        "org/mozilla/javascript/ScriptRuntime",
1101:                        "checkRegExpProxy", "(Lorg/mozilla/javascript/Context;"
1102:                                + ")Lorg/mozilla/javascript/RegExpProxy;");
1103:                // Stack: proxy, array
1104:                cfw.add(ByteCode.DUP);
1105:                cfw.addALoad(contextArg);
1106:                cfw.addInvoke(ByteCode.INVOKESTATIC, mainClassName,
1107:                        REGEXP_INIT_METHOD_NAME, REGEXP_INIT_METHOD_SIGNATURE);
1108:                for (int i = 0; i != regexpCount; ++i) {
1109:                    // Stack: proxy, array
1110:                    cfw.add(ByteCode.DUP2);
1111:                    cfw.addALoad(contextArg);
1112:                    cfw.addALoad(scopeArg);
1113:                    cfw.add(ByteCode.GETSTATIC, mainClassName,
1114:                            getCompiledRegexpName(n, i), "Ljava/lang/Object;");
1115:                    // Stack: compiledRegExp, scope, cx, proxy, array, proxy, array
1116:                    cfw.addInvoke(ByteCode.INVOKEINTERFACE,
1117:                            "org/mozilla/javascript/RegExpProxy", "wrapRegExp",
1118:                            "(Lorg/mozilla/javascript/Context;"
1119:                                    + "Lorg/mozilla/javascript/Scriptable;"
1120:                                    + "Ljava/lang/Object;"
1121:                                    + ")Lorg/mozilla/javascript/Scriptable;");
1122:                    // Stack: wrappedRegExp, array, proxy, array
1123:                    cfw.addPush(i);
1124:                    cfw.add(ByteCode.SWAP);
1125:                    cfw.add(ByteCode.AASTORE);
1126:                    // Stack: proxy, array
1127:                }
1128:                // remove proxy
1129:                cfw.add(ByteCode.POP);
1130:            }
1131:
1132:            void pushNumberAsObject(ClassFileWriter cfw, double num) {
1133:                if (num == 0.0) {
1134:                    if (1 / num > 0) {
1135:                        // +0.0
1136:                        cfw.add(ByteCode.GETSTATIC,
1137:                                "org/mozilla/javascript/optimizer/OptRuntime",
1138:                                "zeroObj", "Ljava/lang/Double;");
1139:                    } else {
1140:                        cfw.addPush(num);
1141:                        addDoubleWrap(cfw);
1142:                    }
1143:
1144:                } else if (num == 1.0) {
1145:                    cfw.add(ByteCode.GETSTATIC,
1146:                            "org/mozilla/javascript/optimizer/OptRuntime",
1147:                            "oneObj", "Ljava/lang/Double;");
1148:                    return;
1149:
1150:                } else if (num == -1.0) {
1151:                    cfw.add(ByteCode.GETSTATIC,
1152:                            "org/mozilla/javascript/optimizer/OptRuntime",
1153:                            "minusOneObj", "Ljava/lang/Double;");
1154:
1155:                } else if (num != num) {
1156:                    cfw.add(ByteCode.GETSTATIC,
1157:                            "org/mozilla/javascript/ScriptRuntime", "NaNobj",
1158:                            "Ljava/lang/Double;");
1159:
1160:                } else if (itsConstantListSize >= 2000) {
1161:                    // There appears to be a limit in the JVM on either the number
1162:                    // of static fields in a class or the size of the class
1163:                    // initializer. Either way, we can't have any more than 2000
1164:                    // statically init'd constants.
1165:                    cfw.addPush(num);
1166:                    addDoubleWrap(cfw);
1167:
1168:                } else {
1169:                    int N = itsConstantListSize;
1170:                    int index = 0;
1171:                    if (N == 0) {
1172:                        itsConstantList = new double[64];
1173:                    } else {
1174:                        double[] array = itsConstantList;
1175:                        while (index != N && array[index] != num) {
1176:                            ++index;
1177:                        }
1178:                        if (N == array.length) {
1179:                            array = new double[N * 2];
1180:                            System.arraycopy(itsConstantList, 0, array, 0, N);
1181:                            itsConstantList = array;
1182:                        }
1183:                    }
1184:                    if (index == N) {
1185:                        itsConstantList[N] = num;
1186:                        itsConstantListSize = N + 1;
1187:                    }
1188:                    String constantName = "_k" + index;
1189:                    String constantType = getStaticConstantWrapperType(num);
1190:                    cfw.add(ByteCode.GETSTATIC, mainClassName, constantName,
1191:                            constantType);
1192:                }
1193:            }
1194:
1195:            private static void addDoubleWrap(ClassFileWriter cfw) {
1196:                cfw.addInvoke(ByteCode.INVOKESTATIC,
1197:                        "org/mozilla/javascript/optimizer/OptRuntime",
1198:                        "wrapDouble", "(D)Ljava/lang/Double;");
1199:            }
1200:
1201:            private static String getStaticConstantWrapperType(double num) {
1202:                int inum = (int) num;
1203:                if (inum == num) {
1204:                    return "Ljava/lang/Integer;";
1205:                } else {
1206:                    return "Ljava/lang/Double;";
1207:                }
1208:            }
1209:
1210:            static void pushUndefined(ClassFileWriter cfw) {
1211:                cfw.add(ByteCode.GETSTATIC, "org/mozilla/javascript/Undefined",
1212:                        "instance", "Ljava/lang/Object;");
1213:            }
1214:
1215:            int getIndex(ScriptOrFnNode n) {
1216:                return scriptOrFnIndexes.getExisting(n);
1217:            }
1218:
1219:            static String getDirectTargetFieldName(int i) {
1220:                return "_dt" + i;
1221:            }
1222:
1223:            String getDirectCtorName(ScriptOrFnNode n) {
1224:                return "_n" + getIndex(n);
1225:            }
1226:
1227:            String getBodyMethodName(ScriptOrFnNode n) {
1228:                return "_c" + getIndex(n);
1229:            }
1230:
1231:            String getBodyMethodSignature(ScriptOrFnNode n) {
1232:                StringBuffer sb = new StringBuffer();
1233:                sb.append('(');
1234:                sb.append(mainClassSignature);
1235:                sb.append("Lorg/mozilla/javascript/Context;"
1236:                        + "Lorg/mozilla/javascript/Scriptable;"
1237:                        + "Lorg/mozilla/javascript/Scriptable;");
1238:                if (n.getType() == Token.FUNCTION) {
1239:                    OptFunctionNode ofn = OptFunctionNode.get(n);
1240:                    if (ofn.isTargetOfDirectCall()) {
1241:                        int pCount = ofn.fnode.getParamCount();
1242:                        for (int i = 0; i != pCount; i++) {
1243:                            sb.append("Ljava/lang/Object;D");
1244:                        }
1245:                    }
1246:                }
1247:                sb.append("[Ljava/lang/Object;)Ljava/lang/Object;");
1248:                return sb.toString();
1249:            }
1250:
1251:            String getFunctionInitMethodName(OptFunctionNode ofn) {
1252:                return "_i" + getIndex(ofn.fnode);
1253:            }
1254:
1255:            String getCompiledRegexpName(ScriptOrFnNode n, int regexpIndex) {
1256:                return "_re" + getIndex(n) + "_" + regexpIndex;
1257:            }
1258:
1259:            static RuntimeException badTree() {
1260:                throw new RuntimeException("Bad tree in codegen");
1261:            }
1262:
1263:            void setMainMethodClass(String className) {
1264:                mainMethodClass = className;
1265:            }
1266:
1267:            static final String DEFAULT_MAIN_METHOD_CLASS = "org.mozilla.javascript.optimizer.OptRuntime";
1268:
1269:            private static final String SUPER_CLASS_NAME = "org.mozilla.javascript.NativeFunction";
1270:
1271:            static final String DIRECT_CALL_PARENT_FIELD = "_dcp";
1272:            private static final String ID_FIELD_NAME = "_id";
1273:
1274:            private static final String REGEXP_INIT_METHOD_NAME = "_reInit";
1275:            private static final String REGEXP_INIT_METHOD_SIGNATURE = "(Lorg/mozilla/javascript/RegExpProxy;"
1276:                    + "Lorg/mozilla/javascript/Context;" + ")V";
1277:            static final String REGEXP_ARRAY_FIELD_NAME = "_re";
1278:            static final String REGEXP_ARRAY_FIELD_TYPE = "[Ljava/lang/Object;";
1279:
1280:            static final String FUNCTION_INIT_SIGNATURE = "(Lorg/mozilla/javascript/Context;"
1281:                    + "Lorg/mozilla/javascript/Scriptable;" + ")V";
1282:
1283:            static final String FUNCTION_CONSTRUCTOR_SIGNATURE = "(Lorg/mozilla/javascript/Scriptable;"
1284:                    + "Lorg/mozilla/javascript/Context;I)V";
1285:
1286:            private static final Object globalLock = new Object();
1287:            private static int globalSerialClassCounter;
1288:
1289:            private CompilerEnvirons compilerEnv;
1290:
1291:            private ObjArray directCallTargets;
1292:            ScriptOrFnNode[] scriptOrFnNodes;
1293:            private ObjToIntMap scriptOrFnIndexes;
1294:
1295:            private String mainMethodClass = DEFAULT_MAIN_METHOD_CLASS;
1296:
1297:            String mainClassName;
1298:            String mainClassSignature;
1299:
1300:            private double[] itsConstantList;
1301:            private int itsConstantListSize;
1302:        }
1303:
1304:        class BodyCodegen {
1305:            void generateBodyCode() {
1306:                isGenerator = Codegen.isGenerator(scriptOrFn);
1307:
1308:                // generate the body of the current function or script object
1309:                initBodyGeneration();
1310:
1311:                if (isGenerator) {
1312:
1313:                    // All functions in the generated bytecode have a unique name. Every
1314:                    // generator has a unique prefix followed by _gen
1315:                    String type = "(" + codegen.mainClassSignature
1316:                            + "Lorg/mozilla/javascript/Context;"
1317:                            + "Lorg/mozilla/javascript/Scriptable;"
1318:                            + "Ljava/lang/Object;"
1319:                            + "Ljava/lang/Object;I)Ljava/lang/Object;";
1320:                    cfw
1321:                            .startMethod(
1322:                                    codegen.getBodyMethodName(scriptOrFn)
1323:                                            + "_gen",
1324:                                    type,
1325:                                    (short) (ClassFileWriter.ACC_STATIC | ClassFileWriter.ACC_PRIVATE));
1326:                } else {
1327:                    cfw
1328:                            .startMethod(
1329:                                    codegen.getBodyMethodName(scriptOrFn),
1330:                                    codegen.getBodyMethodSignature(scriptOrFn),
1331:                                    (short) (ClassFileWriter.ACC_STATIC | ClassFileWriter.ACC_PRIVATE));
1332:                }
1333:
1334:                generatePrologue();
1335:                Node treeTop;
1336:                if (fnCurrent != null) {
1337:                    treeTop = scriptOrFn.getLastChild();
1338:                } else {
1339:                    treeTop = scriptOrFn;
1340:                }
1341:                generateStatement(treeTop);
1342:                generateEpilogue();
1343:
1344:                cfw.stopMethod((short) (localsMax + 1));
1345:
1346:                if (isGenerator) {
1347:                    // generate the user visible method which when invoked will
1348:                    // return a generator object
1349:                    generateGenerator();
1350:                }
1351:            }
1352:
1353:            // This creates a the user-facing function that returns a NativeGenerator
1354:            // object.
1355:            private void generateGenerator() {
1356:                cfw
1357:                        .startMethod(
1358:                                codegen.getBodyMethodName(scriptOrFn),
1359:                                codegen.getBodyMethodSignature(scriptOrFn),
1360:                                (short) (ClassFileWriter.ACC_STATIC | ClassFileWriter.ACC_PRIVATE));
1361:
1362:                initBodyGeneration();
1363:                argsLocal = firstFreeLocal++;
1364:                localsMax = firstFreeLocal;
1365:
1366:                // get top level scope
1367:                if (fnCurrent != null
1368:                        && !inDirectCallFunction
1369:                        && (!compilerEnv.isUseDynamicScope() || fnCurrent.fnode
1370:                                .getIgnoreDynamicScope())) {
1371:                    // Unless we're either in a direct call or using dynamic scope,
1372:                    // use the enclosing scope of the function as our variable object.
1373:                    cfw.addALoad(funObjLocal);
1374:                    cfw.addInvoke(ByteCode.INVOKEINTERFACE,
1375:                            "org/mozilla/javascript/Scriptable",
1376:                            "getParentScope",
1377:                            "()Lorg/mozilla/javascript/Scriptable;");
1378:                    cfw.addAStore(variableObjectLocal);
1379:                }
1380:
1381:                // generators are forced to have an activation record
1382:                cfw.addALoad(funObjLocal);
1383:                cfw.addALoad(variableObjectLocal);
1384:                cfw.addALoad(argsLocal);
1385:                addScriptRuntimeInvoke("createFunctionActivation",
1386:                        "(Lorg/mozilla/javascript/NativeFunction;"
1387:                                + "Lorg/mozilla/javascript/Scriptable;"
1388:                                + "[Ljava/lang/Object;"
1389:                                + ")Lorg/mozilla/javascript/Scriptable;");
1390:                cfw.addAStore(variableObjectLocal);
1391:
1392:                // create a function object
1393:                cfw.add(ByteCode.NEW, codegen.mainClassName);
1394:                // Call function constructor
1395:                cfw.add(ByteCode.DUP);
1396:                cfw.addALoad(variableObjectLocal);
1397:                cfw.addALoad(contextLocal); // load 'cx'
1398:                cfw.addPush(scriptOrFnIndex);
1399:                cfw.addInvoke(ByteCode.INVOKESPECIAL, codegen.mainClassName,
1400:                        "<init>", Codegen.FUNCTION_CONSTRUCTOR_SIGNATURE);
1401:
1402:                // Init mainScript field
1403:                cfw.add(ByteCode.DUP);
1404:                if (isTopLevel)
1405:                    Kit.codeBug(); // Only functions can be generators
1406:                cfw.add(ByteCode.ALOAD_0);
1407:                cfw.add(ByteCode.GETFIELD, codegen.mainClassName,
1408:                        Codegen.DIRECT_CALL_PARENT_FIELD,
1409:                        codegen.mainClassSignature);
1410:                cfw.add(ByteCode.PUTFIELD, codegen.mainClassName,
1411:                        Codegen.DIRECT_CALL_PARENT_FIELD,
1412:                        codegen.mainClassSignature);
1413:
1414:                generateNestedFunctionInits();
1415:
1416:                // create the NativeGenerator object that we return
1417:                cfw.addALoad(variableObjectLocal);
1418:                cfw.addALoad(this ObjLocal);
1419:                cfw.addLoadConstant(maxLocals);
1420:                cfw.addLoadConstant(maxStack);
1421:                addOptRuntimeInvoke("createNativeGenerator",
1422:                        "(Lorg/mozilla/javascript/NativeFunction;"
1423:                                + "Lorg/mozilla/javascript/Scriptable;"
1424:                                + "Lorg/mozilla/javascript/Scriptable;II"
1425:                                + ")Lorg/mozilla/javascript/Scriptable;");
1426:
1427:                cfw.add(ByteCode.ARETURN);
1428:                cfw.stopMethod((short) (localsMax + 1));
1429:            }
1430:
1431:            private void generateNestedFunctionInits() {
1432:                int functionCount = scriptOrFn.getFunctionCount();
1433:                for (int i = 0; i != functionCount; i++) {
1434:                    OptFunctionNode ofn = OptFunctionNode.get(scriptOrFn, i);
1435:                    if (ofn.fnode.getFunctionType() == FunctionNode.FUNCTION_STATEMENT) {
1436:                        visitFunction(ofn, FunctionNode.FUNCTION_STATEMENT);
1437:                    }
1438:                }
1439:            }
1440:
1441:            private void initBodyGeneration() {
1442:                isTopLevel = (scriptOrFn == codegen.scriptOrFnNodes[0]);
1443:
1444:                varRegisters = null;
1445:                if (scriptOrFn.getType() == Token.FUNCTION) {
1446:                    fnCurrent = OptFunctionNode.get(scriptOrFn);
1447:                    hasVarsInRegs = !fnCurrent.fnode.requiresActivation();
1448:                    if (hasVarsInRegs) {
1449:                        int n = fnCurrent.fnode.getParamAndVarCount();
1450:                        if (n != 0) {
1451:                            varRegisters = new short[n];
1452:                        }
1453:                    }
1454:                    inDirectCallFunction = fnCurrent.isTargetOfDirectCall();
1455:                    if (inDirectCallFunction && !hasVarsInRegs)
1456:                        Codegen.badTree();
1457:                } else {
1458:                    fnCurrent = null;
1459:                    hasVarsInRegs = false;
1460:                    inDirectCallFunction = false;
1461:                }
1462:
1463:                locals = new int[MAX_LOCALS];
1464:
1465:                funObjLocal = 0;
1466:                contextLocal = 1;
1467:                variableObjectLocal = 2;
1468:                this ObjLocal = 3;
1469:                localsMax = (short) 4; // number of parms + "this"
1470:                firstFreeLocal = 4;
1471:
1472:                popvLocal = -1;
1473:                argsLocal = -1;
1474:                itsZeroArgArray = -1;
1475:                itsOneArgArray = -1;
1476:                scriptRegexpLocal = -1;
1477:                epilogueLabel = -1;
1478:                enterAreaStartLabel = -1;
1479:                generatorStateLocal = -1;
1480:            }
1481:
1482:            /**
1483:             * Generate the prologue for a function or script.
1484:             */
1485:            private void generatePrologue() {
1486:                if (inDirectCallFunction) {
1487:                    int directParameterCount = scriptOrFn.getParamCount();
1488:                    // 0 is reserved for function Object 'this'
1489:                    // 1 is reserved for context
1490:                    // 2 is reserved for parentScope
1491:                    // 3 is reserved for script 'this'
1492:                    if (firstFreeLocal != 4)
1493:                        Kit.codeBug();
1494:                    for (int i = 0; i != directParameterCount; ++i) {
1495:                        varRegisters[i] = firstFreeLocal;
1496:                        // 3 is 1 for Object parm and 2 for double parm
1497:                        firstFreeLocal += 3;
1498:                    }
1499:                    if (!fnCurrent.getParameterNumberContext()) {
1500:                        // make sure that all parameters are objects
1501:                        itsForcedObjectParameters = true;
1502:                        for (int i = 0; i != directParameterCount; ++i) {
1503:                            short reg = varRegisters[i];
1504:                            cfw.addALoad(reg);
1505:                            cfw.add(ByteCode.GETSTATIC, "java/lang/Void",
1506:                                    "TYPE", "Ljava/lang/Class;");
1507:                            int isObjectLabel = cfw.acquireLabel();
1508:                            cfw.add(ByteCode.IF_ACMPNE, isObjectLabel);
1509:                            cfw.addDLoad(reg + 1);
1510:                            addDoubleWrap();
1511:                            cfw.addAStore(reg);
1512:                            cfw.markLabel(isObjectLabel);
1513:                        }
1514:                    }
1515:                }
1516:
1517:                if (fnCurrent != null
1518:                        && !inDirectCallFunction
1519:                        && (!compilerEnv.isUseDynamicScope() || fnCurrent.fnode
1520:                                .getIgnoreDynamicScope())) {
1521:                    // Unless we're either in a direct call or using dynamic scope,
1522:                    // use the enclosing scope of the function as our variable object.
1523:                    cfw.addALoad(funObjLocal);
1524:                    cfw.addInvoke(ByteCode.INVOKEINTERFACE,
1525:                            "org/mozilla/javascript/Scriptable",
1526:                            "getParentScope",
1527:                            "()Lorg/mozilla/javascript/Scriptable;");
1528:                    cfw.addAStore(variableObjectLocal);
1529:                }
1530:
1531:                // reserve 'args[]'
1532:                argsLocal = firstFreeLocal++;
1533:                localsMax = firstFreeLocal;
1534:
1535:                // Generate Generator specific prelude
1536:                if (isGenerator) {
1537:
1538:                    // reserve 'args[]'
1539:                    operationLocal = firstFreeLocal++;
1540:                    localsMax = firstFreeLocal;
1541:
1542:                    // Local 3 is a reference to a GeneratorState object. The rest
1543:                    // of codegen expects local 3 to be a reference to the thisObj.
1544:                    // So move the value in local 3 to generatorStateLocal, and load
1545:                    // the saved thisObj from the GeneratorState object.
1546:                    cfw.addALoad(this ObjLocal);
1547:                    generatorStateLocal = firstFreeLocal++;
1548:                    localsMax = firstFreeLocal;
1549:                    cfw.add(ByteCode.CHECKCAST,
1550:                            OptRuntime.GeneratorState.CLASS_NAME);
1551:                    cfw.add(ByteCode.DUP);
1552:                    cfw.addAStore(generatorStateLocal);
1553:                    cfw.add(ByteCode.GETFIELD,
1554:                            OptRuntime.GeneratorState.CLASS_NAME,
1555:                            OptRuntime.GeneratorState.this Obj_NAME,
1556:                            OptRuntime.GeneratorState.this Obj_TYPE);
1557:                    cfw.addAStore(this ObjLocal);
1558:
1559:                    if (epilogueLabel == -1) {
1560:                        epilogueLabel = cfw.acquireLabel();
1561:                    }
1562:
1563:                    ArrayList targets = ((FunctionNode) scriptOrFn)
1564:                            .getResumptionPoints();
1565:                    if (targets != null) {
1566:                        // get resumption point
1567:                        generateGetGeneratorResumptionPoint();
1568:
1569:                        // generate dispatch table
1570:                        generatorSwitch = cfw.addTableSwitch(0, targets.size()
1571:                                + GENERATOR_START);
1572:                        generateCheckForThrowOrClose(-1, false, GENERATOR_START);
1573:                    }
1574:                }
1575:
1576:                if (fnCurrent == null) {
1577:                    // See comments in case Token.REGEXP
1578:                    if (scriptOrFn.getRegexpCount() != 0) {
1579:                        scriptRegexpLocal = getNewWordLocal();
1580:                        codegen.pushRegExpArray(cfw, scriptOrFn, contextLocal,
1581:                                variableObjectLocal);
1582:                        cfw.addAStore(scriptRegexpLocal);
1583:                    }
1584:                }
1585:
1586:                if (compilerEnv.isGenerateObserverCount())
1587:                    saveCurrentCodeOffset();
1588:
1589:                if (hasVarsInRegs) {
1590:                    // No need to create activation. Pad arguments if need be.
1591:                    int parmCount = scriptOrFn.getParamCount();
1592:                    if (parmCount > 0 && !inDirectCallFunction) {
1593:                        // Set up args array
1594:                        // check length of arguments, pad if need be
1595:                        cfw.addALoad(argsLocal);
1596:                        cfw.add(ByteCode.ARRAYLENGTH);
1597:                        cfw.addPush(parmCount);
1598:                        int label = cfw.acquireLabel();
1599:                        cfw.add(ByteCode.IF_ICMPGE, label);
1600:                        cfw.addALoad(argsLocal);
1601:                        cfw.addPush(parmCount);
1602:                        addScriptRuntimeInvoke("padArguments",
1603:                                "([Ljava/lang/Object;I"
1604:                                        + ")[Ljava/lang/Object;");
1605:                        cfw.addAStore(argsLocal);
1606:                        cfw.markLabel(label);
1607:                    }
1608:
1609:                    int paramCount = fnCurrent.fnode.getParamCount();
1610:                    int varCount = fnCurrent.fnode.getParamAndVarCount();
1611:                    boolean[] constDeclarations = fnCurrent.fnode
1612:                            .getParamAndVarConst();
1613:
1614:                    // REMIND - only need to initialize the vars that don't get a value
1615:                    // before the next call and are used in the function
1616:                    short firstUndefVar = -1;
1617:                    for (int i = 0; i != varCount; ++i) {
1618:                        short reg = -1;
1619:                        if (i < paramCount) {
1620:                            if (!inDirectCallFunction) {
1621:                                reg = getNewWordLocal();
1622:                                cfw.addALoad(argsLocal);
1623:                                cfw.addPush(i);
1624:                                cfw.add(ByteCode.AALOAD);
1625:                                cfw.addAStore(reg);
1626:                            }
1627:                        } else if (fnCurrent.isNumberVar(i)) {
1628:                            reg = getNewWordPairLocal(constDeclarations[i]);
1629:                            cfw.addPush(0.0);
1630:                            cfw.addDStore(reg);
1631:                        } else {
1632:                            reg = getNewWordLocal(constDeclarations[i]);
1633:                            if (firstUndefVar == -1) {
1634:                                Codegen.pushUndefined(cfw);
1635:                                firstUndefVar = reg;
1636:                            } else {
1637:                                cfw.addALoad(firstUndefVar);
1638:                            }
1639:                            cfw.addAStore(reg);
1640:                        }
1641:                        if (reg >= 0) {
1642:                            if (constDeclarations[i]) {
1643:                                cfw.addPush(0);
1644:                                cfw.addIStore(reg
1645:                                        + (fnCurrent.isNumberVar(i) ? 2 : 1));
1646:                            }
1647:                            varRegisters[i] = reg;
1648:                        }
1649:
1650:                        // Add debug table entry if we're generating debug info
1651:                        if (compilerEnv.isGenerateDebugInfo()) {
1652:                            String name = fnCurrent.fnode.getParamOrVarName(i);
1653:                            String type = fnCurrent.isNumberVar(i) ? "D"
1654:                                    : "Ljava/lang/Object;";
1655:                            int startPC = cfw.getCurrentCodeOffset();
1656:                            if (reg < 0) {
1657:                                reg = varRegisters[i];
1658:                            }
1659:                            cfw.addVariableDescriptor(name, type, startPC, reg);
1660:                        }
1661:                    }
1662:
1663:                    // Skip creating activation object.
1664:                    return;
1665:                }
1666:
1667:                // skip creating activation object for the body of a generator. The
1668:                // activation record required by a generator has already been created
1669:                // in generateGenerator().
1670:                if (isGenerator)
1671:                    return;
1672:
1673:                String debugVariableName;
1674:                if (fnCurrent != null) {
1675:                    debugVariableName = "activation";
1676:                    cfw.addALoad(funObjLocal);
1677:                    cfw.addALoad(variableObjectLocal);
1678:                    cfw.addALoad(argsLocal);
1679:                    addScriptRuntimeInvoke("createFunctionActivation",
1680:                            "(Lorg/mozilla/javascript/NativeFunction;"
1681:                                    + "Lorg/mozilla/javascript/Scriptable;"
1682:                                    + "[Ljava/lang/Object;"
1683:                                    + ")Lorg/mozilla/javascript/Scriptable;");
1684:                    cfw.addAStore(variableObjectLocal);
1685:                    cfw.addALoad(contextLocal);
1686:                    cfw.addALoad(variableObjectLocal);
1687:                    addScriptRuntimeInvoke("enterActivationFunction",
1688:                            "(Lorg/mozilla/javascript/Context;"
1689:                                    + "Lorg/mozilla/javascript/Scriptable;"
1690:                                    + ")V");
1691:                } else {
1692:                    debugVariableName = "global";
1693:                    cfw.addALoad(funObjLocal);
1694:                    cfw.addALoad(this ObjLocal);
1695:                    cfw.addALoad(contextLocal);
1696:                    cfw.addALoad(variableObjectLocal);
1697:                    cfw.addPush(0); // false to indicate it is not eval script
1698:                    addScriptRuntimeInvoke("initScript",
1699:                            "(Lorg/mozilla/javascript/NativeFunction;"
1700:                                    + "Lorg/mozilla/javascript/Scriptable;"
1701:                                    + "Lorg/mozilla/javascript/Context;"
1702:                                    + "Lorg/mozilla/javascript/Scriptable;"
1703:                                    + "Z" + ")V");
1704:                }
1705:
1706:                enterAreaStartLabel = cfw.acquireLabel();
1707:                epilogueLabel = cfw.acquireLabel();
1708:                cfw.markLabel(enterAreaStartLabel);
1709:
1710:                generateNestedFunctionInits();
1711:
1712:                // default is to generate debug info
1713:                if (compilerEnv.isGenerateDebugInfo()) {
1714:                    cfw.addVariableDescriptor(debugVariableName,
1715:                            "Lorg/mozilla/javascript/Scriptable;", cfw
1716:                                    .getCurrentCodeOffset(),
1717:                            variableObjectLocal);
1718:                }
1719:
1720:                if (fnCurrent == null) {
1721:                    // OPT: use dataflow to prove that this assignment is dead
1722:                    popvLocal = getNewWordLocal();
1723:                    Codegen.pushUndefined(cfw);
1724:                    cfw.addAStore(popvLocal);
1725:
1726:                    int linenum = scriptOrFn.getEndLineno();
1727:                    if (linenum != -1)
1728:                        cfw.addLineNumberEntry((short) linenum);
1729:
1730:                } else {
1731:                    if (fnCurrent.itsContainsCalls0) {
1732:                        itsZeroArgArray = getNewWordLocal();
1733:                        cfw.add(ByteCode.GETSTATIC,
1734:                                "org/mozilla/javascript/ScriptRuntime",
1735:                                "emptyArgs", "[Ljava/lang/Object;");
1736:                        cfw.addAStore(itsZeroArgArray);
1737:                    }
1738:                    if (fnCurrent.itsContainsCalls1) {
1739:                        itsOneArgArray = getNewWordLocal();
1740:                        cfw.addPush(1);
1741:                        cfw.add(ByteCode.ANEWARRAY, "java/lang/Object");
1742:                        cfw.addAStore(itsOneArgArray);
1743:                    }
1744:                }
1745:            }
1746:
1747:            private void generateGetGeneratorResumptionPoint() {
1748:                cfw.addALoad(generatorStateLocal);
1749:                cfw.add(ByteCode.GETFIELD,
1750:                        OptRuntime.GeneratorState.CLASS_NAME,
1751:                        OptRuntime.GeneratorState.resumptionPoint_NAME,
1752:                        OptRuntime.GeneratorState.resumptionPoint_TYPE);
1753:            }
1754:
1755:            private void generateSetGeneratorResumptionPoint(int nextState) {
1756:                cfw.addALoad(generatorStateLocal);
1757:                cfw.addLoadConstant(nextState);
1758:                cfw.add(ByteCode.PUTFIELD,
1759:                        OptRuntime.GeneratorState.CLASS_NAME,
1760:                        OptRuntime.GeneratorState.resumptionPoint_NAME,
1761:                        OptRuntime.GeneratorState.resumptionPoint_TYPE);
1762:            }
1763:
1764:            private void generateGetGeneratorStackState() {
1765:                cfw.addALoad(generatorStateLocal);
1766:                addOptRuntimeInvoke("getGeneratorStackState",
1767:                        "(Ljava/lang/Object;)[Ljava/lang/Object;");
1768:            }
1769:
1770:            private void generateEpilogue() {
1771:                if (compilerEnv.isGenerateObserverCount())
1772:                    addInstructionCount();
1773:                if (isGenerator) {
1774:                    // generate locals initialization
1775:                    HashMap liveLocals = ((FunctionNode) scriptOrFn)
1776:                            .getLiveLocals();
1777:                    if (liveLocals != null) {
1778:                        ArrayList nodes = ((FunctionNode) scriptOrFn)
1779:                                .getResumptionPoints();
1780:                        for (int i = 0; i < nodes.size(); i++) {
1781:                            Node node = (Node) nodes.get(i);
1782:                            int[] live = (int[]) liveLocals.get(node);
1783:                            if (live != null) {
1784:                                cfw.markTableSwitchCase(generatorSwitch,
1785:                                        getNextGeneratorState(node));
1786:                                generateGetGeneratorLocalsState();
1787:                                for (int j = 0; j < live.length; j++) {
1788:                                    cfw.add(ByteCode.DUP);
1789:                                    cfw.addLoadConstant(j);
1790:                                    cfw.add(ByteCode.AALOAD);
1791:                                    cfw.addAStore(live[j]);
1792:                                }
1793:                                cfw.add(ByteCode.POP);
1794:                                cfw.add(ByteCode.GOTO, getTargetLabel(node));
1795:                            }
1796:                        }
1797:                    }
1798:
1799:                    // generate dispatch tables for finally
1800:                    if (finallys != null) {
1801:                        Enumeration en = finallys.keys();
1802:                        while (en.hasMoreElements()) {
1803:                            Node n = (Node) en.nextElement();
1804:                            if (n.getType() == Token.FINALLY) {
1805:                                FinallyReturnPoint ret = (FinallyReturnPoint) finallys
1806:                                        .get(n);
1807:                                // the finally will jump here
1808:                                cfw.markLabel(ret.tableLabel, (short) 1);
1809:
1810:                                // start generating a dispatch table
1811:                                int startSwitch = cfw.addTableSwitch(0,
1812:                                        ret.jsrPoints.size() - 1);
1813:                                int c = 0;
1814:                                cfw.markTableSwitchDefault(startSwitch);
1815:                                for (int i = 0; i < ret.jsrPoints.size(); i++) {
1816:                                    // generate gotos back to the JSR location
1817:                                    cfw.markTableSwitchCase(startSwitch, c);
1818:                                    cfw.add(ByteCode.GOTO,
1819:                                            ((Integer) ret.jsrPoints.get(i))
1820:                                                    .intValue());
1821:                                    c++;
1822:                                }
1823:                            }
1824:                        }
1825:                    }
1826:                }
1827:
1828:                if (epilogueLabel != -1) {
1829:                    cfw.markLabel(epilogueLabel);
1830:                }
1831:
1832:                if (hasVarsInRegs) {
1833:                    cfw.add(ByteCode.ARETURN);
1834:                    return;
1835:                } else if (isGenerator) {
1836:                    if (((FunctionNode) scriptOrFn).getResumptionPoints() != null) {
1837:                        cfw.markTableSwitchDefault(generatorSwitch);
1838:                    }
1839:
1840:                    // change state for re-entry
1841:                    generateSetGeneratorResumptionPoint(GENERATOR_TERMINATE);
1842:
1843:                    // throw StopIteration
1844:                    cfw.addALoad(variableObjectLocal);
1845:                    addOptRuntimeInvoke("throwStopIteration",
1846:                            "(Ljava/lang/Object;)V");
1847:
1848:                    Codegen.pushUndefined(cfw);
1849:                    cfw.add(ByteCode.ARETURN);
1850:
1851:                } else if (fnCurrent == null) {
1852:                    cfw.addALoad(popvLocal);
1853:                    cfw.add(ByteCode.ARETURN);
1854:                } else {
1855:                    generateActivationExit();
1856:                    cfw.add(ByteCode.ARETURN);
1857:
1858:                    // Generate catch block to catch all and rethrow to call exit code
1859:                    // under exception propagation as well.
1860:
1861:                    int finallyHandler = cfw.acquireLabel();
1862:                    cfw.markHandler(finallyHandler);
1863:                    short exceptionObject = getNewWordLocal();
1864:                    cfw.addAStore(exceptionObject);
1865:
1866:                    // Duplicate generateActivationExit() in the catch block since it
1867:                    // takes less space then full-featured ByteCode.JSR/ByteCode.RET
1868:                    generateActivationExit();
1869:
1870:                    cfw.addALoad(exceptionObject);
1871:                    releaseWordLocal(exceptionObject);
1872:                    // rethrow
1873:                    cfw.add(ByteCode.ATHROW);
1874:
1875:                    // mark the handler
1876:                    cfw.addExceptionHandler(enterAreaStartLabel, epilogueLabel,
1877:                            finallyHandler, null); // catch any
1878:                }
1879:            }
1880:
1881:            private void generateGetGeneratorLocalsState() {
1882:                cfw.addALoad(generatorStateLocal);
1883:                addOptRuntimeInvoke("getGeneratorLocalsState",
1884:                        "(Ljava/lang/Object;)[Ljava/lang/Object;");
1885:            }
1886:
1887:            private void generateActivationExit() {
1888:                if (fnCurrent == null || hasVarsInRegs)
1889:                    throw Kit.codeBug();
1890:                cfw.addALoad(contextLocal);
1891:                addScriptRuntimeInvoke("exitActivationFunction",
1892:                        "(Lorg/mozilla/javascript/Context;)V");
1893:            }
1894:
1895:            private void generateStatement(Node node) {
1896:                updateLineNumber(node);
1897:                int type = node.getType();
1898:                Node child = node.getFirstChild();
1899:                switch (type) {
1900:                case Token.LOOP:
1901:                case Token.LABEL:
1902:                case Token.WITH:
1903:                case Token.SCRIPT:
1904:                case Token.BLOCK:
1905:                case Token.EMPTY:
1906:                    // no-ops.
1907:                    while (child != null) {
1908:                        generateStatement(child);
1909:                        child = child.getNext();
1910:                    }
1911:                    break;
1912:
1913:                case Token.LOCAL_BLOCK: {
1914:                    int local = getNewWordLocal();
1915:                    if (isGenerator) {
1916:                        cfw.add(ByteCode.ACONST_NULL);
1917:                        cfw.addAStore(local);
1918:                    }
1919:                    node.putIntProp(Node.LOCAL_PROP, local);
1920:                    while (child != null) {
1921:                        generateStatement(child);
1922:                        child = child.getNext();
1923:                    }
1924:                    releaseWordLocal((short) local);
1925:                    node.removeProp(Node.LOCAL_PROP);
1926:                    break;
1927:                }
1928:
1929:                case Token.FUNCTION: {
1930:                    int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP);
1931:                    OptFunctionNode ofn = OptFunctionNode.get(scriptOrFn,
1932:                            fnIndex);
1933:                    int t = ofn.fnode.getFunctionType();
1934:                    if (t == FunctionNode.FUNCTION_EXPRESSION_STATEMENT) {
1935:                        visitFunction(ofn, t);
1936:                    } else {
1937:                        if (t != FunctionNode.FUNCTION_STATEMENT) {
1938:                            throw Codegen.badTree();
1939:                        }
1940:                    }
1941:                    break;
1942:                }
1943:
1944:                case Token.TRY:
1945:                    visitTryCatchFinally((Node.Jump) node, child);
1946:                    break;
1947:
1948:                case Token.CATCH_SCOPE: {
1949:                    // nothing stays on the stack on entry into a catch scope
1950:                    cfw.setStackTop((short) 0);
1951:
1952:                    int local = getLocalBlockRegister(node);
1953:                    int scopeIndex = node
1954:                            .getExistingIntProp(Node.CATCH_SCOPE_PROP);
1955:
1956:                    String name = child.getString(); // name of exception
1957:                    child = child.getNext();
1958:                    generateExpression(child, node); // load expression object
1959:                    if (scopeIndex == 0) {
1960:                        cfw.add(ByteCode.ACONST_NULL);
1961:                    } else {
1962:                        // Load previous catch scope object
1963:                        cfw.addALoad(local);
1964:                    }
1965:                    cfw.addPush(name);
1966:                    cfw.addALoad(contextLocal);
1967:                    cfw.addALoad(variableObjectLocal);
1968:
1969:                    addScriptRuntimeInvoke("newCatchScope",
1970:                            "(Ljava/lang/Throwable;"
1971:                                    + "Lorg/mozilla/javascript/Scriptable;"
1972:                                    + "Ljava/lang/String;"
1973:                                    + "Lorg/mozilla/javascript/Context;"
1974:                                    + "Lorg/mozilla/javascript/Scriptable;"
1975:                                    + ")Lorg/mozilla/javascript/Scriptable;");
1976:                    cfw.addAStore(local);
1977:                }
1978:                    break;
1979:
1980:                case Token.THROW:
1981:                    generateExpression(child, node);
1982:                    if (compilerEnv.isGenerateObserverCount())
1983:                        addInstructionCount();
1984:                    generateThrowJavaScriptException();
1985:                    break;
1986:
1987:                case Token.RETHROW:
1988:                    if (compilerEnv.isGenerateObserverCount())
1989:                        addInstructionCount();
1990:                    cfw.addALoad(getLocalBlockRegister(node));
1991:                    cfw.add(ByteCode.ATHROW);
1992:                    break;
1993:
1994:                case Token.RETURN_RESULT:
1995:                case Token.RETURN:
1996:                    if (!isGenerator) {
1997:                        if (child != null) {
1998:                            generateExpression(child, node);
1999:                        } else if (type == Token.RETURN) {
2000:                            Codegen.pushUndefined(cfw);
2001:                        } else {
2002:                            if (popvLocal < 0)
2003:                                throw Codegen.badTree();
2004:                            cfw.addALoad(popvLocal);
2005:                        }
2006:                    }
2007:                    if (compilerEnv.isGenerateObserverCount())
2008:                        addInstructionCount();
2009:                    if (epilogueLabel == -1) {
2010:                        if (!hasVarsInRegs)
2011:                            throw Codegen.badTree();
2012:                        epilogueLabel = cfw.acquireLabel();
2013:                    }
2014:                    cfw.add(ByteCode.GOTO, epilogueLabel);
2015:                    break;
2016:
2017:                case Token.SWITCH:
2018:                    if (compilerEnv.isGenerateObserverCount())
2019:                        addInstructionCount();
2020:                    visitSwitch((Node.Jump) node, child);
2021:                    break;
2022:
2023:                case Token.ENTERWITH:
2024:                    generateExpression(child, node);
2025:                    cfw.addALoad(contextLocal);
2026:                    cfw.addALoad(variableObjectLocal);
2027:                    addScriptRuntimeInvoke("enterWith", "(Ljava/lang/Object;"
2028:                            + "Lorg/mozilla/javascript/Context;"
2029:                            + "Lorg/mozilla/javascript/Scriptable;"
2030:                            + ")Lorg/mozilla/javascript/Scriptable;");
2031:                    cfw.addAStore(variableObjectLocal);
2032:                    incReferenceWordLocal(variableObjectLocal);
2033:                    break;
2034:
2035:                case Token.LEAVEWITH:
2036:                    cfw.addALoad(variableObjectLocal);
2037:                    addScriptRuntimeInvoke("leaveWith",
2038:                            "(Lorg/mozilla/javascript/Scriptable;"
2039:                                    + ")Lorg/mozilla/javascript/Scriptable;");
2040:                    cfw.addAStore(variableObjectLocal);
2041:                    decReferenceWordLocal(variableObjectLocal);
2042:                    break;
2043:
2044:                case Token.ENUM_INIT_KEYS:
2045:                case Token.ENUM_INIT_VALUES:
2046:                case Token.ENUM_INIT_ARRAY:
2047:                    generateExpression(child, node);
2048:                    cfw.addALoad(contextLocal);
2049:                    int enumType = type == Token.ENUM_INIT_KEYS ? ScriptRuntime.ENUMERATE_KEYS
2050:                            : type == Token.ENUM_INIT_VALUES ? ScriptRuntime.ENUMERATE_VALUES
2051:                                    : ScriptRuntime.ENUMERATE_ARRAY;
2052:                    cfw.addPush(enumType);
2053:                    addScriptRuntimeInvoke("enumInit", "(Ljava/lang/Object;"
2054:                            + "Lorg/mozilla/javascript/Context;" + "I"
2055:                            + ")Ljava/lang/Object;");
2056:                    cfw.addAStore(getLocalBlockRegister(node));
2057:                    break;
2058:
2059:                case Token.EXPR_VOID:
2060:                    if (child.getType() == Token.SETVAR) {
2061:                        /* special case this so as to avoid unnecessary
2062:                        load's & pop's */
2063:                        visitSetVar(child, child.getFirstChild(), false);
2064:                    } else if (child.getType() == Token.SETCONSTVAR) {
2065:                        /* special case this so as to avoid unnecessary
2066:                        load's & pop's */
2067:                        visitSetConstVar(child, child.getFirstChild(), false);
2068:                    } else if (child.getType() == Token.YIELD) {
2069:                        generateYieldPoint(child, false);
2070:                    } else {
2071:                        generateExpression(child, node);
2072:                        if (node.getIntProp(Node.ISNUMBER_PROP, -1) != -1)
2073:                            cfw.add(ByteCode.POP2);
2074:                        else
2075:                            cfw.add(ByteCode.POP);
2076:                    }
2077:                    break;
2078:
2079:                case Token.EXPR_RESULT:
2080:                    generateExpression(child, node);
2081:                    if (popvLocal < 0) {
2082:                        popvLocal = getNewWordLocal();
2083:                    }
2084:                    cfw.addAStore(popvLocal);
2085:                    break;
2086:
2087:                case Token.TARGET: {
2088:                    if (compilerEnv.isGenerateObserverCount())
2089:                        addInstructionCount();
2090:                    int label = getTargetLabel(node);
2091:                    cfw.markLabel(label);
2092:                    if (compilerEnv.isGenerateObserverCount())
2093:                        saveCurrentCodeOffset();
2094:                }
2095:                    break;
2096:
2097:                case Token.JSR:
2098:                case Token.GOTO:
2099:                case Token.IFEQ:
2100:                case Token.IFNE:
2101:                    if (compilerEnv.isGenerateObserverCount())
2102:                        addInstructionCount();
2103:                    visitGoto((Node.Jump) node, type, child);
2104:                    break;
2105:
2106:                case Token.FINALLY: {
2107:                    if (compilerEnv.isGenerateObserverCount())
2108:                        saveCurrentCodeOffset();
2109:                    // there is exactly one value on the stack when enterring
2110:                    // finally blocks: the return address (or its int encoding)
2111:                    cfw.setStackTop((short) 1);
2112:
2113:                    // Save return address in a new local
2114:                    int finallyRegister = getNewWordLocal();
2115:                    if (isGenerator)
2116:                        generateIntegerWrap();
2117:                    cfw.addAStore(finallyRegister);
2118:
2119:                    while (child != null) {
2120:                        generateStatement(child);
2121:                        child = child.getNext();
2122:                    }
2123:                    if (isGenerator) {
2124:                        cfw.addALoad(finallyRegister);
2125:                        cfw.add(ByteCode.CHECKCAST, "java/lang/Integer");
2126:                        generateIntegerUnwrap();
2127:                        FinallyReturnPoint ret = (FinallyReturnPoint) finallys
2128:                                .get(node);
2129:                        ret.tableLabel = cfw.acquireLabel();
2130:                        cfw.add(ByteCode.GOTO, ret.tableLabel);
2131:                    } else {
2132:                        cfw.add(ByteCode.RET, finallyRegister);
2133:                    }
2134:                    releaseWordLocal((short) finallyRegister);
2135:                }
2136:                    break;
2137:
2138:                case Token.DEBUGGER:
2139:                    break;
2140:
2141:                default:
2142:                    throw Codegen.badTree();
2143:                }
2144:
2145:            }
2146:
2147:            private void generateIntegerWrap() {
2148:                cfw.addInvoke(ByteCode.INVOKESTATIC, "java/lang/Integer",
2149:                        "valueOf", "(I)Ljava/lang/Integer;");
2150:            }
2151:
2152:            private void generateIntegerUnwrap() {
2153:                cfw.addInvoke(ByteCode.INVOKEVIRTUAL, "java/lang/Integer",
2154:                        "intValue", "()I");
2155:            }
2156:
2157:            private void generateThrowJavaScriptException() {
2158:                cfw.add(ByteCode.NEW,
2159:                        "org/mozilla/javascript/JavaScriptException");
2160:                cfw.add(ByteCode.DUP_X1);
2161:                cfw.add(ByteCode.SWAP);
2162:                cfw.addPush(scriptOrFn.getSourceName());
2163:                cfw.addPush(itsLineNumber);
2164:                cfw.addInvoke(ByteCode.INVOKESPECIAL,
2165:                        "org/mozilla/javascript/JavaScriptException", "<init>",
2166:                        "(Ljava/lang/Object;Ljava/lang/String;I)V");
2167:                cfw.add(ByteCode.ATHROW);
2168:            }
2169:
2170:            private int getNextGeneratorState(Node node) {
2171:                int nodeIndex = ((FunctionNode) scriptOrFn)
2172:                        .getResumptionPoints().indexOf(node);
2173:                return nodeIndex + GENERATOR_YIELD_START;
2174:            }
2175:
2176:            private void generateExpression(Node node, Node parent) {
2177:                int type = node.getType();
2178:                Node child = node.getFirstChild();
2179:                switch (type) {
2180:                case Token.USE_STACK:
2181:                    break;
2182:
2183:                case Token.FUNCTION:
2184:                    if (fnCurrent != null || parent.getType() != Token.SCRIPT) {
2185:                        int fnIndex = node
2186:                                .getExistingIntProp(Node.FUNCTION_PROP);
2187:                        OptFunctionNode ofn = OptFunctionNode.get(scriptOrFn,
2188:                                fnIndex);
2189:                        int t = ofn.fnode.getFunctionType();
2190:                        if (t != FunctionNode.FUNCTION_EXPRESSION) {
2191:                            throw Codegen.badTree();
2192:                        }
2193:                        visitFunction(ofn, t);
2194:                    }
2195:                    break;
2196:
2197:                case Token.NAME: {
2198:                    cfw.addALoad(contextLocal);
2199:                    cfw.addALoad(variableObjectLocal);
2200:                    cfw.addPush(node.getString());
2201:                    addScriptRuntimeInvoke("name",
2202:                            "(Lorg/mozilla/javascript/Context;"
2203:                                    + "Lorg/mozilla/javascript/Scriptable;"
2204:                                    + "Ljava/lang/String;"
2205:                                    + ")Ljava/lang/Object;");
2206:                }
2207:                    break;
2208:
2209:                case Token.CALL:
2210:                case Token.NEW: {
2211:                    int specialType = node.getIntProp(Node.SPECIALCALL_PROP,
2212:                            Node.NON_SPECIALCALL);
2213:                    if (specialType == Node.NON_SPECIALCALL) {
2214:                        OptFunctionNode target;
2215:                        target = (OptFunctionNode) node
2216:                                .getProp(Node.DIRECTCALL_PROP);
2217:
2218:                        if (target != null) {
2219:                            visitOptimizedCall(node, target, type, child);
2220:                        } else if (type == Token.CALL) {
2221:                            visitStandardCall(node, child);
2222:                        } else {
2223:                            visitStandardNew(node, child);
2224:                        }
2225:                    } else {
2226:                        visitSpecialCall(node, type, specialType, child);
2227:                    }
2228:                }
2229:                    break;
2230:
2231:                case Token.REF_CALL:
2232:                    generateFunctionAndThisObj(child, node);
2233:                    // stack: ... functionObj thisObj
2234:                    child = child.getNext();
2235:                    generateCallArgArray(node, child, false);
2236:                    cfw.addALoad(contextLocal);
2237:                    addScriptRuntimeInvoke("callRef",
2238:                            "(Lorg/mozilla/javascript/Callable;"
2239:                                    + "Lorg/mozilla/javascript/Scriptable;"
2240:                                    + "[Ljava/lang/Object;"
2241:                                    + "Lorg/mozilla/javascript/Context;"
2242:                                    + ")Lorg/mozilla/javascript/Ref;");
2243:                    break;
2244:
2245:                case Token.NUMBER: {
2246:                    double num = node.getDouble();
2247:                    if (node.getIntProp(Node.ISNUMBER_PROP, -1) != -1) {
2248:                        cfw.addPush(num);
2249:                    } else {
2250:                        codegen.pushNumberAsObject(cfw, num);
2251:                    }
2252:                }
2253:                    break;
2254:
2255:                case Token.STRING:
2256:                    cfw.addPush(node.getString());
2257:                    break;
2258:
2259:                case Token.THIS:
2260:                    cfw.addALoad(this ObjLocal);
2261:                    break;
2262:
2263:                case Token.THISFN:
2264:                    cfw.add(ByteCode.ALOAD_0);
2265:                    break;
2266:
2267:                case Token.NULL:
2268:                    cfw.add(ByteCode.ACONST_NULL);
2269:                    break;
2270:
2271:                case Token.TRUE:
2272:                    cfw.add(ByteCode.GETSTATIC, "java/lang/Boolean", "TRUE",
2273:                            "Ljava/lang/Boolean;");
2274:                    break;
2275:
2276:                case Token.FALSE:
2277:                    cfw.add(ByteCode.GETSTATIC, "java/lang/Boolean", "FALSE",
2278:                            "Ljava/lang/Boolean;");
2279:                    break;
2280:
2281:                case Token.REGEXP: {
2282:                    int i = node.getExistingIntProp(Node.REGEXP_PROP);
2283:                    // Scripts can not use REGEXP_ARRAY_FIELD_NAME since
2284:                    // it it will make script.exec non-reentrant so they
2285:                    // store regexp array in a local variable while
2286:                    // functions always access precomputed
2287:                    // REGEXP_ARRAY_FIELD_NAME not to consume locals
2288:                    if (fnCurrent == null) {
2289:                        cfw.addALoad(scriptRegexpLocal);
2290:                    } else {
2291:                        cfw.addALoad(funObjLocal);
2292:                        cfw.add(ByteCode.GETFIELD, codegen.mainClassName,
2293:                                Codegen.REGEXP_ARRAY_FIELD_NAME,
2294:                                Codegen.REGEXP_ARRAY_FIELD_TYPE);
2295:                    }
2296:                    cfw.addPush(i);
2297:                    cfw.add(ByteCode.AALOAD);
2298:                }
2299:                    break;
2300:
2301:                case Token.COMMA: {
2302:                    Node next = child.getNext();
2303:                    while (next != null) {
2304:                        generateExpression(child, node);
2305:                        cfw.add(ByteCode.POP);
2306:                        child = next;
2307:                        next = next.getNext();
2308:                    }
2309:                    generateExpression(child, node);
2310:                    break;
2311:                }
2312:
2313:                case Token.ENUM_NEXT:
2314:                case Token.ENUM_ID: {
2315:                    int local = getLocalBlockRegister(node);
2316:                    cfw.addALoad(local);
2317:                    if (type == Token.ENUM_NEXT) {
2318:                        addScriptRuntimeInvoke("enumNext",
2319:                                "(Ljava/lang/Object;)Ljava/lang/Boolean;");
2320:                    } else {
2321:                        cfw.addALoad(contextLocal);
2322:                        addScriptRuntimeInvoke("enumId", "(Ljava/lang/Object;"
2323:                                + "Lorg/mozilla/javascript/Context;"
2324:                                + ")Ljava/lang/Object;");
2325:                    }
2326:                    break;
2327:                }
2328:
2329:                case Token.ARRAYLIT:
2330:                    visitArrayLiteral(node, child);
2331:                    break;
2332:
2333:                case Token.OBJECTLIT:
2334:                    visitObjectLiteral(node, child);
2335:                    break;
2336:
2337:                case Token.NOT: {
2338:                    int trueTarget = cfw.acquireLabel();
2339:                    int falseTarget = cfw.acquireLabel();
2340:                    int beyond = cfw.acquireLabel();
2341:                    generateIfJump(child, node, trueTarget, falseTarget);
2342:
2343:                    cfw.markLabel(trueTarget);
2344:                    cfw.add(ByteCode.GETSTATIC, "java/lang/Boolean", "FALSE",
2345:                            "Ljava/lang/Boolean;");
2346:                    cfw.add(ByteCode.GOTO, beyond);
2347:                    cfw.markLabel(falseTarget);
2348:                    cfw.add(ByteCode.GETSTATIC, "java/lang/Boolean", "TRUE",
2349:                            "Ljava/lang/Boolean;");
2350:                    cfw.markLabel(beyond);
2351:                    cfw.adjustStackTop(-1);
2352:                    break;
2353:                }
2354:
2355:                case Token.BITNOT:
2356:                    generateExpression(child, node);
2357:                    addScriptRuntimeInvoke("toInt32", "(Ljava/lang/Object;)I");
2358:                    cfw.addPush(-1); // implement ~a as (a ^ -1)
2359:                    cfw.add(ByteCode.IXOR);
2360:                    cfw.add(ByteCode.I2D);
2361:                    addDoubleWrap();
2362:                    break;
2363:
2364:                case Token.VOID:
2365:                    generateExpression(child, node);
2366:                    cfw.add(ByteCode.POP);
2367:                    Codegen.pushUndefined(cfw);
2368:                    break;
2369:
2370:                case Token.TYPEOF:
2371:                    generateExpression(child, node);
2372:                    addScriptRuntimeInvoke("typeof", "(Ljava/lang/Object;"
2373:                            + ")Ljava/lang/String;");
2374:                    break;
2375:
2376:                case Token.TYPEOFNAME:
2377:                    visitTypeofname(node);
2378:                    break;
2379:
2380:                case Token.INC:
2381:                case Token.DEC:
2382:                    visitIncDec(node);
2383:                    break;
2384:
2385:                case Token.OR:
2386:                case Token.AND: {
2387:                    generateExpression(child, node);
2388:                    cfw.add(ByteCode.DUP);
2389:                    addScriptRuntimeInvoke("toBoolean", "(Ljava/lang/Object;)Z");
2390:                    int falseTarget = cfw.acquireLabel();
2391:                    if (type == Token.AND)
2392:                        cfw.add(ByteCode.IFEQ, falseTarget);
2393:                    else
2394:                        cfw.add(ByteCode.IFNE, falseTarget);
2395:                    cfw.add(ByteCode.POP);
2396:                    generateExpression(child.getNext(), node);
2397:                    cfw.markLabel(falseTarget);
2398:                }
2399:                    break;
2400:
2401:                case Token.HOOK: {
2402:                    Node ifThen = child.getNext();
2403:                    Node ifElse = ifThen.getNext();
2404:                    generateExpression(child, node);
2405:                    addScriptRuntimeInvoke("toBoolean", "(Ljava/lang/Object;)Z");
2406:                    int elseTarget = cfw.acquireLabel();
2407:                    cfw.add(ByteCode.IFEQ, elseTarget);
2408:                    short stack = cfw.getStackTop();
2409:                    generateExpression(ifThen, node);
2410:                    int afterHook = cfw.acquireLabel();
2411:                    cfw.add(ByteCode.GOTO, afterHook);
2412:                    cfw.markLabel(elseTarget, stack);
2413:                    generateExpression(ifElse, node);
2414:                    cfw.markLabel(afterHook);
2415:                }
2416:                    break;
2417:
2418:                case Token.ADD: {
2419:                    generateExpression(child, node);
2420:                    generateExpression(child.getNext(), node);
2421:                    switch (node.getIntProp(Node.ISNUMBER_PROP, -1)) {
2422:                    case Node.BOTH:
2423:                        cfw.add(ByteCode.DADD);
2424:                        break;
2425:                    case Node.LEFT:
2426:                        addOptRuntimeInvoke("add",
2427:                                "(DLjava/lang/Object;)Ljava/lang/Object;");
2428:                        break;
2429:                    case Node.RIGHT:
2430:                        addOptRuntimeInvoke("add",
2431:                                "(Ljava/lang/Object;D)Ljava/lang/Object;");
2432:                        break;
2433:                    default:
2434:                        if (child.getType() == Token.STRING) {
2435:                            addScriptRuntimeInvoke("add", "(Ljava/lang/String;"
2436:                                    + "Ljava/lang/Object;"
2437:                                    + ")Ljava/lang/String;");
2438:                        } else if (child.getNext().getType() == Token.STRING) {
2439:                            addScriptRuntimeInvoke("add", "(Ljava/lang/Object;"
2440:                                    + "Ljava/lang/String;"
2441:                                    + ")Ljava/lang/String;");
2442:                        } else {
2443:                            cfw.addALoad(contextLocal);
2444:                            addScriptRuntimeInvoke("add", "(Ljava/lang/Object;"
2445:                                    + "Ljava/lang/Object;"
2446:                                    + "Lorg/mozilla/javascript/Context;"
2447:                                    + ")Ljava/lang/Object;");
2448:                        }
2449:                    }
2450:                }
2451:                    break;
2452:
2453:                case Token.MUL:
2454:                    visitArithmetic(node, ByteCode.DMUL, child, parent);
2455:                    break;
2456:
2457:                case Token.SUB:
2458:                    visitArithmetic(node, ByteCode.DSUB, child, parent);
2459:                    break;
2460:
2461:                case Token.DIV:
2462:                case Token.MOD:
2463:                    visitArithmetic(node, type == Token.DIV ? ByteCode.DDIV
2464:                            : ByteCode.DREM, child, parent);
2465:                    break;
2466:
2467:                case Token.BITOR:
2468:                case Token.BITXOR:
2469:                case Token.BITAND:
2470:                case Token.LSH:
2471:                case Token.RSH:
2472:                case Token.URSH:
2473:                    visitBitOp(node, type, child);
2474:                    break;
2475:
2476:                case Token.POS:
2477:                case Token.NEG:
2478:                    generateExpression(child, node);
2479:                    addObjectToDouble();
2480:                    if (type == Token.NEG) {
2481:                        cfw.add(ByteCode.DNEG);
2482:                    }
2483:                    addDoubleWrap();
2484:                    break;
2485:
2486:                case Token.TO_DOUBLE:
2487:                    // cnvt to double (not Double)
2488:                    generateExpression(child, node);
2489:                    addObjectToDouble();
2490:                    break;
2491:
2492:                case Token.TO_OBJECT: {
2493:                    // convert from double
2494:                    int prop = -1;
2495:                    if (child.getType() == Token.NUMBER) {
2496:                        prop = child.getIntProp(Node.ISNUMBER_PROP, -1);
2497:                    }
2498:                    if (prop != -1) {
2499:                        child.removeProp(Node.ISNUMBER_PROP);
2500:                        generateExpression(child, node);
2501:                        child.putIntProp(Node.ISNUMBER_PROP, prop);
2502:                    } else {
2503:                        generateExpression(child, node);
2504:                        addDoubleWrap();
2505:                    }
2506:                    break;
2507:                }
2508:
2509:                case Token.IN:
2510:                case Token.INSTANCEOF:
2511:                case Token.LE:
2512:                case Token.LT:
2513:                case Token.GE:
2514:                case Token.GT: {
2515:                    int trueGOTO = cfw.acquireLabel();
2516:                    int falseGOTO = cfw.acquireLabel();
2517:                    visitIfJumpRelOp(node, child, trueGOTO, falseGOTO);
2518:                    addJumpedBooleanWrap(trueGOTO, falseGOTO);
2519:                    break;
2520:                }
2521:
2522:                case Token.EQ:
2523:                case Token.NE:
2524:                case Token.SHEQ:
2525:                case Token.SHNE: {
2526:                    int trueGOTO = cfw.acquireLabel();
2527:                    int falseGOTO = cfw.acquireLabel();
2528:                    visitIfJumpEqOp(node, child, trueGOTO, falseGOTO);
2529:                    addJumpedBooleanWrap(trueGOTO, falseGOTO);
2530:                    break;
2531:                }
2532:
2533:                case Token.GETPROP:
2534:                case Token.GETPROPNOWARN:
2535:                    visitGetProp(node, child);
2536:                    break;
2537:
2538:                case Token.GETELEM:
2539:                    generateExpression(child, node); // object
2540:                    generateExpression(child.getNext(), node); // id
2541:                    cfw.addALoad(contextLocal);
2542:                    if (node.getIntProp(Node.ISNUMBER_PROP, -1) != -1) {
2543:                        addScriptRuntimeInvoke("getObjectIndex",
2544:                                "(Ljava/lang/Object;D"
2545:                                        + "Lorg/mozilla/javascript/Context;"
2546:                                        + ")Ljava/lang/Object;");
2547:                    } else {
2548:                        addScriptRuntimeInvoke("getObjectElem",
2549:                                "(Ljava/lang/Object;" + "Ljava/lang/Object;"
2550:                                        + "Lorg/mozilla/javascript/Context;"
2551:                                        + ")Ljava/lang/Object;");
2552:                    }
2553:                    break;
2554:
2555:                case Token.GET_REF:
2556:                    generateExpression(child, node); // reference
2557:                    cfw.addALoad(contextLocal);
2558:                    addScriptRuntimeInvoke("refGet",
2559:                            "(Lorg/mozilla/javascript/Ref;"
2560:                                    + "Lorg/mozilla/javascript/Context;"
2561:                                    + ")Ljava/lang/Object;");
2562:                    break;
2563:
2564:                case Token.GETVAR:
2565:                    visitGetVar(node);
2566:                    break;
2567:
2568:                case Token.SETVAR:
2569:                    visitSetVar(node, child, true);
2570:                    break;
2571:
2572:                case Token.SETNAME:
2573:                    visitSetName(node, child);
2574:                    break;
2575:
2576:                case Token.SETCONST:
2577:                    visitSetConst(node, child);
2578:                    break;
2579:
2580:                case Token.SETCONSTVAR:
2581:                    visitSetConstVar(node, child, true);
2582:                    break;
2583:
2584:                case Token.SETPROP:
2585:                case Token.SETPROP_OP:
2586:                    visitSetProp(type, node, child);
2587:                    break;
2588:
2589:                case Token.SETELEM:
2590:                case Token.SETELEM_OP:
2591:                    visitSetElem(type, node, child);
2592:                    break;
2593:
2594:                case Token.SET_REF:
2595:                case Token.SET_REF_OP: {
2596:                    generateExpression(child, node);
2597:                    child = child.getNext();
2598:                    if (type == Token.SET_REF_OP) {
2599:                        cfw.add(ByteCode.DUP);
2600:                        cfw.addALoad(contextLocal);
2601:                        addScriptRuntimeInvoke("refGet",
2602:                                "(Lorg/mozilla/javascript/Ref;"
2603:                                        + "Lorg/mozilla/javascript/Context;"
2604:                                        + ")Ljava/lang/Object;");
2605:                    }
2606:                    generateExpression(child, node);
2607:                    cfw.addALoad(contextLocal);
2608:                    addScriptRuntimeInvoke("refSet",
2609:                            "(Lorg/mozilla/javascript/Ref;"
2610:                                    + "Ljava/lang/Object;"
2611:                                    + "Lorg/mozilla/javascript/Context;"
2612:                                    + ")Ljava/lang/Object;");
2613:                }
2614:                    break;
2615:
2616:                case Token.DEL_REF:
2617:                    generateExpression(child, node);
2618:                    cfw.addALoad(contextLocal);
2619:                    addScriptRuntimeInvoke("refDel",
2620:                            "(Lorg/mozilla/javascript/Ref;"
2621:                                    + "Lorg/mozilla/javascript/Context;"
2622:                                    + ")Ljava/lang/Object;");
2623:                    break;
2624:
2625:                case Token.DELPROP:
2626:                    generateExpression(child, node);
2627:                    child = child.getNext();
2628:                    generateExpression(child, node);
2629:                    cfw.addALoad(contextLocal);
2630:                    addScriptRuntimeInvoke("delete", "(Ljava/lang/Object;"
2631:                            + "Ljava/lang/Object;"
2632:                            + "Lorg/mozilla/javascript/Context;"
2633:                            + ")Ljava/lang/Object;");
2634:                    break;
2635:
2636:                case Token.BINDNAME: {
2637:                    while (child != null) {
2638:                        generateExpression(child, node);
2639:                        child = child.getNext();
2640:                    }
2641:                    // Generate code for "ScriptRuntime.bind(varObj, "s")"
2642:                    cfw.addALoad(contextLocal);
2643:                    cfw.addALoad(variableObjectLocal);
2644:                    cfw.addPush(node.getString());
2645:                    addScriptRuntimeInvoke("bind",
2646:                            "(Lorg/mozilla/javascript/Context;"
2647:                                    + "Lorg/mozilla/javascript/Scriptable;"
2648:                                    + "Ljava/lang/String;"
2649:                                    + ")Lorg/mozilla/javascript/Scriptable;");
2650:                }
2651:                    break;
2652:
2653:                case Token.LOCAL_LOAD:
2654:                    cfw.addALoad(getLocalBlockRegister(node));
2655:                    break;
2656:
2657:                case Token.REF_SPECIAL: {
2658:                    String special = (String) node.getProp(Node.NAME_PROP);
2659:                    generateExpression(child, node);
2660:                    cfw.addPush(special);
2661:                    cfw.addALoad(contextLocal);
2662:                    addScriptRuntimeInvoke("specialRef", "(Ljava/lang/Object;"
2663:                            + "Ljava/lang/String;"
2664:                            + "Lorg/mozilla/javascript/Context;"
2665:                            + ")Lorg/mozilla/javascript/Ref;");
2666:                }
2667:                    break;
2668:
2669:                case Token.REF_MEMBER:
2670:                case Token.REF_NS_MEMBER:
2671:                case Token.REF_NAME:
2672:                case Token.REF_NS_NAME: {
2673:                    int memberTypeFlags = node.getIntProp(
2674:                            Node.MEMBER_TYPE_PROP, 0);
2675:                    // generate possible target, possible namespace and member
2676:                    do {
2677:                        generateExpression(child, node);
2678:                        child = child.getNext();
2679:                    } while (child != null);
2680:                    cfw.addALoad(contextLocal);
2681:                    String methodName, signature;
2682:                    switch (type) {
2683:                    case Token.REF_MEMBER:
2684:                        methodName = "memberRef";
2685:                        signature = "(Ljava/lang/Object;"
2686:                                + "Ljava/lang/Object;"
2687:                                + "Lorg/mozilla/javascript/Context;" + "I"
2688:                                + ")Lorg/mozilla/javascript/Ref;";
2689:                        break;
2690:                    case Token.REF_NS_MEMBER:
2691:                        methodName = "memberRef";
2692:                        signature = "(Ljava/lang/Object;"
2693:                                + "Ljava/lang/Object;" + "Ljava/lang/Object;"
2694:                                + "Lorg/mozilla/javascript/Context;" + "I"
2695:                                + ")Lorg/mozilla/javascript/Ref;";
2696:                        break;
2697:                    case Token.REF_NAME:
2698:                        methodName = "nameRef";
2699:                        signature = "(Ljava/lang/Object;"
2700:                                + "Lorg/mozilla/javascript/Context;"
2701:                                + "Lorg/mozilla/javascript/Scriptable;" + "I"
2702:                                + ")Lorg/mozilla/javascript/Ref;";
2703:                        cfw.addALoad(variableObjectLocal);
2704:                        break;
2705:                    case Token.REF_NS_NAME:
2706:                        methodName = "nameRef";
2707:                        signature = "(Ljava/lang/Object;"
2708:                                + "Lorg/mozilla/javascript/Context;"
2709:                                + "Lorg/mozilla/javascript/Scriptable;" + "I"
2710:                                + ")Lorg/mozilla/javascript/Ref;";
2711:                        cfw.addALoad(variableObjectLocal);
2712:                        break;
2713:                    default:
2714:                        throw Kit.codeBug();
2715:                    }
2716:                    cfw.addPush(memberTypeFlags);
2717:                    addScriptRuntimeInvoke(methodName, signature);
2718:                }
2719:                    break;
2720:
2721:                case Token.DOTQUERY:
2722:                    visitDotQuery(node, child);
2723:                    break;
2724:
2725:                case Token.ESCXMLATTR:
2726:                    generateExpression(child, node);
2727:                    cfw.addALoad(contextLocal);
2728:                    addScriptRuntimeInvoke("escapeAttributeValue",
2729:                            "(Ljava/lang/Object;"
2730:                                    + "Lorg/mozilla/javascript/Context;"
2731:                                    + ")Ljava/lang/String;");
2732:                    break;
2733:
2734:                case Token.ESCXMLTEXT:
2735:                    generateExpression(child, node);
2736:                    cfw.addALoad(contextLocal);
2737:                    addScriptRuntimeInvoke("escapeTextValue",
2738:                            "(Ljava/lang/Object;"
2739:                                    + "Lorg/mozilla/javascript/Context;"
2740:                                    + ")Ljava/lang/String;");
2741:                    break;
2742:
2743:                case Token.DEFAULTNAMESPACE:
2744:                    generateExpression(child, node);
2745:                    cfw.addALoad(contextLocal);
2746:                    addScriptRuntimeInvoke("setDefaultNamespace",
2747:                            "(Ljava/lang/Object;"
2748:                                    + "Lorg/mozilla/javascript/Context;"
2749:                                    + ")Ljava/lang/Object;");
2750:                    break;
2751:
2752:                case Token.YIELD:
2753:                    generateYieldPoint(node, true);
2754:                    break;
2755:
2756:                case Token.WITHEXPR: {
2757:                    Node enterWith = child;
2758:                    Node with = enterWith.getNext();
2759:                    Node leaveWith = with.getNext();
2760:                    generateStatement(enterWith);
2761:                    generateExpression(with.getFirstChild(), with);
2762:                    generateStatement(leaveWith);
2763:                    break;
2764:                }
2765:
2766:                case Token.ARRAYCOMP: {
2767:                    Node initStmt = child;
2768:                    Node expr = child.getNext();
2769:                    generateStatement(initStmt);
2770:                    generateExpression(expr, node);
2771:                    break;
2772:                }
2773:
2774:                default:
2775:                    throw new RuntimeException("Unexpected node type " + type);
2776:                }
2777:
2778:            }
2779:
2780:            private void generateYieldPoint(Node node, boolean exprContext) {
2781:                // save stack state
2782:                int top = cfw.getStackTop();
2783:                maxStack = maxStack > top ? maxStack : top;
2784:                if (cfw.getStackTop() != 0) {
2785:                    generateGetGeneratorStackState();
2786:                    for (int i = 0; i < top; i++) {
2787:                        cfw.add(ByteCode.DUP_X1);
2788:                        cfw.add(ByteCode.SWAP);
2789:                        cfw.addLoadConstant(i);
2790:                        cfw.add(ByteCode.SWAP);
2791:                        cfw.add(ByteCode.AASTORE);
2792:                    }
2793:                    // pop the array object
2794:                    cfw.add(ByteCode.POP);
2795:                }
2796:
2797:                // generate the yield argument
2798:                Node child = node.getFirstChild();
2799:                if (child != null)
2800:                    generateExpression(child, node);
2801:                else
2802:                    Codegen.pushUndefined(cfw);
2803:
2804:                // change the resumption state
2805:                int nextState = getNextGeneratorState(node);
2806:                generateSetGeneratorResumptionPoint(nextState);
2807:
2808:                boolean hasLocals = generateSaveLocals(node);
2809:
2810:                cfw.add(ByteCode.ARETURN);
2811:
2812:                generateCheckForThrowOrClose(getTargetLabel(node), hasLocals,
2813:                        nextState);
2814:
2815:                // reconstruct the stack
2816:                if (top != 0) {
2817:                    generateGetGeneratorStackState();
2818:                    for (int i = 0; i < top; i++) {
2819:                        cfw.add(ByteCode.DUP);
2820:                        cfw.addLoadConstant(top - i - 1);
2821:                        cfw.add(ByteCode.AALOAD);
2822:                        cfw.add(ByteCode.SWAP);
2823:                    }
2824:                    cfw.add(ByteCode.POP);
2825:                }
2826:
2827:                // load return value from yield
2828:                if (exprContext) {
2829:                    cfw.addALoad(argsLocal);
2830:                }
2831:            }
2832:
2833:            private void generateCheckForThrowOrClose(int label,
2834:                    boolean hasLocals, int nextState) {
2835:                int throwLabel = cfw.acquireLabel();
2836:                int closeLabel = cfw.acquireLabel();
2837:
2838:                // throw the user provided object, if the operation is .throw()
2839:                cfw.markLabel(throwLabel);
2840:                cfw.addALoad(argsLocal);
2841:                generateThrowJavaScriptException();
2842:
2843:                // throw our special internal exception if the generator is being closed
2844:                cfw.markLabel(closeLabel);
2845:                cfw.addALoad(argsLocal);
2846:                cfw.add(ByteCode.CHECKCAST, "java/lang/Throwable");
2847:                cfw.add(ByteCode.ATHROW);
2848:
2849:                // mark the re-entry point
2850:                // jump here after initializing the locals
2851:                if (label != -1)
2852:                    cfw.markLabel(label);
2853:                if (!hasLocals) {
2854:                    // jump here directly if there are no locals
2855:                    cfw.markTableSwitchCase(generatorSwitch, nextState);
2856:                }
2857:
2858:                // see if we need to dispatch for .close() or .throw()
2859:                cfw.addILoad(operationLocal);
2860:                cfw.addLoadConstant(NativeGenerator.GENERATOR_CLOSE);
2861:                cfw.add(ByteCode.IF_ICMPEQ, closeLabel);
2862:                cfw.addILoad(operationLocal);
2863:                cfw.addLoadConstant(NativeGenerator.GENERATOR_THROW);
2864:                cfw.add(ByteCode.IF_ICMPEQ, throwLabel);
2865:            }
2866:
2867:            private void generateIfJump(Node node, Node parent, int trueLabel,
2868:                    int falseLabel) {
2869:                // System.out.println("gen code for " + node.toString());
2870:
2871:                int type = node.getType();
2872:                Node child = node.getFirstChild();
2873:
2874:                switch (type) {
2875:                case Token.NOT:
2876:                    generateIfJump(child, node, falseLabel, trueLabel);
2877:                    break;
2878:
2879:                case Token.OR:
2880:                case Token.AND: {
2881:                    int interLabel = cfw.acquireLabel();
2882:                    if (type == Token.AND) {
2883:                        generateIfJump(child, node, interLabel, falseLabel);
2884:                    } else {
2885:                        generateIfJump(child, node, trueLabel, interLabel);
2886:                    }
2887:                    cfw.markLabel(interLabel);
2888:                    child = child.getNext();
2889:                    generateIfJump(child, node, trueLabel, falseLabel);
2890:                    break;
2891:                }
2892:
2893:                case Token.IN:
2894:                case Token.INSTANCEOF:
2895:                case Token.LE:
2896:                case Token.LT:
2897:                case Token.GE:
2898:                case Token.GT:
2899:                    visitIfJumpRelOp(node, child, trueLabel, falseLabel);
2900:                    break;
2901:
2902:                case Token.EQ:
2903:                case Token.NE:
2904:                case Token.SHEQ:
2905:                case Token.SHNE:
2906:                    visitIfJumpEqOp(node, child, trueLabel, falseLabel);
2907:                    break;
2908:
2909:                default:
2910:                    // Generate generic code for non-optimized jump
2911:                    generateExpression(node, parent);
2912:                    addScriptRuntimeInvoke("toBoolean", "(Ljava/lang/Object;)Z");
2913:                    cfw.add(ByteCode.IFNE, trueLabel);
2914:                    cfw.add(ByteCode.GOTO, falseLabel);
2915:                }
2916:            }
2917:
2918:            private void visitFunction(OptFunctionNode ofn, int functionType) {
2919:                int fnIndex = codegen.getIndex(ofn.fnode);
2920:                cfw.add(ByteCode.NEW, codegen.mainClassName);
2921:                // Call function constructor
2922:                cfw.add(ByteCode.DUP);
2923:                cfw.addALoad(variableObjectLocal);
2924:                cfw.addALoad(contextLocal); // load 'cx'
2925:                cfw.addPush(fnIndex);
2926:                cfw.addInvoke(ByteCode.INVOKESPECIAL, codegen.mainClassName,
2927:                        "<init>", Codegen.FUNCTION_CONSTRUCTOR_SIGNATURE);
2928:
2929:                // Init mainScript field;
2930:                cfw.add(ByteCode.DUP);
2931:                if (isTopLevel) {
2932:                    cfw.add(ByteCode.ALOAD_0);
2933:                } else {
2934:                    cfw.add(ByteCode.ALOAD_0);
2935:                    cfw.add(ByteCode.GETFIELD, codegen.mainClassName,
2936:                            Codegen.DIRECT_CALL_PARENT_FIELD,
2937:                            codegen.mainClassSignature);
2938:                }
2939:                cfw.add(ByteCode.PUTFIELD, codegen.mainClassName,
2940:                        Codegen.DIRECT_CALL_PARENT_FIELD,
2941:                        codegen.mainClassSignature);
2942:
2943:                int directTargetIndex = ofn.getDirectTargetIndex();
2944:                if (directTargetIndex >= 0) {
2945:                    cfw.add(ByteCode.DUP);
2946:                    if (isTopLevel) {
2947:                        cfw.add(ByteCode.ALOAD_0);
2948:                    } else {
2949:                        cfw.add(ByteCode.ALOAD_0);
2950:                        cfw.add(ByteCode.GETFIELD, codegen.mainClassName,
2951:                                Codegen.DIRECT_CALL_PARENT_FIELD,
2952:                                codegen.mainClassSignature);
2953:                    }
2954:                    cfw.add(ByteCode.SWAP);
2955:                    cfw.add(ByteCode.PUTFIELD, codegen.mainClassName, Codegen
2956:                            .getDirectTargetFieldName(directTargetIndex),
2957:                            codegen.mainClassSignature);
2958:                }
2959:
2960:                if (functionType == FunctionNode.FUNCTION_EXPRESSION) {
2961:                    // Leave closure object on stack and do not pass it to
2962:                    // initFunction which suppose to connect statements to scope
2963:                    return;
2964:                }
2965:                cfw.addPush(functionType);
2966:                cfw.addALoad(variableObjectLocal);
2967:                cfw.addALoad(contextLocal); // load 'cx'
2968:                addOptRuntimeInvoke("initFunction",
2969:                        "(Lorg/mozilla/javascript/NativeFunction;" + "I"
2970:                                + "Lorg/mozilla/javascript/Scriptable;"
2971:                                + "Lorg/mozilla/javascript/Context;" + ")V");
2972:            }
2973:
2974:            private int getTargetLabel(Node target) {
2975:                int labelId = target.labelId();
2976:                if (labelId == -1) {
2977:                    labelId = cfw.acquireLabel();
2978:                    target.labelId(labelId);
2979:                }
2980:                return labelId;
2981:            }
2982:
2983:            private void visitGoto(Node.Jump node, int type, Node child) {
2984:                Node target = node.target;
2985:                if (type == Token.IFEQ || type == Token.IFNE) {
2986:                    if (child == null)
2987:                        throw Codegen.badTree();
2988:                    int targetLabel = getTargetLabel(target);
2989:                    int fallThruLabel = cfw.acquireLabel();
2990:                    if (type == Token.IFEQ)
2991:                        generateIfJump(child, node, targetLabel, fallThruLabel);
2992:                    else
2993:                        generateIfJump(child, node, fallThruLabel, targetLabel);
2994:                    cfw.markLabel(fallThruLabel);
2995:                } else {
2996:                    if (type == Token.JSR) {
2997:                        if (isGenerator) {
2998:                            addGotoWithReturn(target);
2999:                        } else {
3000:                            addGoto(target, ByteCode.JSR);
3001:                        }
3002:                    } else {
3003:                        addGoto(target, ByteCode.GOTO);
3004:                    }
3005:                }
3006:            }
3007:
3008:            private void addGotoWithReturn(Node target) {
3009:                FinallyReturnPoint ret = (FinallyReturnPoint) finallys
3010:                        .get(target);
3011:                cfw.addLoadConstant(ret.jsrPoints.size());
3012:                addGoto(target, ByteCode.GOTO);
3013:                int retLabel = cfw.acquireLabel();
3014:                cfw.markLabel(retLabel);
3015:                ret.jsrPoints.add(Integer.valueOf(retLabel));
3016:            }
3017:
3018:            private void visitArrayLiteral(Node node, Node child) {
3019:                int count = 0;
3020:                for (Node cursor = child; cursor != null; cursor = cursor
3021:                        .getNext()) {
3022:                    ++count;
3023:                }
3024:                // load array to store array literal objects
3025:                addNewObjectArray(count);
3026:                for (int i = 0; i != count; ++i) {
3027:                    cfw.add(ByteCode.DUP);
3028:                    cfw.addPush(i);
3029:                    generateExpression(child, node);
3030:                    cfw.add(ByteCode.AASTORE);
3031:                    child = child.getNext();
3032:                }
3033:                int[] skipIndexes = (int[]) node
3034:                        .getProp(Node.SKIP_INDEXES_PROP);
3035:                if (skipIndexes == null) {
3036:                    cfw.add(ByteCode.ACONST_NULL);
3037:                    cfw.add(ByteCode.ICONST_0);
3038:                } else {
3039:                    cfw.addPush(OptRuntime.encodeIntArray(skipIndexes));
3040:                    cfw.addPush(skipIndexes.length);
3041:                }
3042:                cfw.addALoad(contextLocal);
3043:                cfw.addALoad(variableObjectLocal);
3044:                addOptRuntimeInvoke("newArrayLiteral", "([Ljava/lang/Object;"
3045:                        + "Ljava/lang/String;" + "I"
3046:                        + "Lorg/mozilla/javascript/Context;"
3047:                        + "Lorg/mozilla/javascript/Scriptable;"
3048:                        + ")Lorg/mozilla/javascript/Scriptable;");
3049:            }
3050:
3051:            private void visitObjectLiteral(Node node, Node child) {
3052:                Object[] properties = (Object[]) node
3053:                        .getProp(Node.OBJECT_IDS_PROP);
3054:                int count = properties.length;
3055:
3056:                // load array with property ids
3057:                addNewObjectArray(count);
3058:                for (int i = 0; i != count; ++i) {
3059:                    cfw.add(ByteCode.DUP);
3060:                    cfw.addPush(i);
3061:                    Object id = properties[i];
3062:                    if (id instanceof  String) {
3063:                        cfw.addPush((String) id);
3064:                    } else {
3065:                        cfw.addPush(((Integer) id).intValue());
3066:                        addScriptRuntimeInvoke("wrapInt",
3067:                                "(I)Ljava/lang/Integer;");
3068:                    }
3069:                    cfw.add(ByteCode.AASTORE);
3070:                }
3071:                // load array with property values
3072:                addNewObjectArray(count);
3073:                Node child2 = child;
3074:                for (int i = 0; i != count; ++i) {
3075:                    cfw.add(ByteCode.DUP);
3076:                    cfw.addPush(i);
3077:                    int childType = child.getType();
3078:                    if (childType == Token.GET) {
3079:                        generateExpression(child.getFirstChild(), node);
3080:                    } else if (childType == Token.SET) {
3081:                        generateExpression(child.getFirstChild(), node);
3082:                    } else {
3083:                        generateExpression(child, node);
3084:                    }
3085:                    cfw.add(ByteCode.AASTORE);
3086:                    child = child.getNext();
3087:                }
3088:                // load array with getterSetter values
3089:                cfw.addPush(count);
3090:                cfw.add(ByteCode.NEWARRAY, ByteCode.T_INT);
3091:                for (int i = 0; i != count; ++i) {
3092:                    cfw.add(ByteCode.DUP);
3093:                    cfw.addPush(i);
3094:                    int childType = child2.getType();
3095:                    if (childType == Token.GET) {
3096:                        cfw.add(ByteCode.ICONST_M1);
3097:                    } else if (childType == Token.SET) {
3098:                        cfw.add(ByteCode.ICONST_1);
3099:                    } else {
3100:                        cfw.add(ByteCode.ICONST_0);
3101:                    }
3102:                    cfw.add(ByteCode.IASTORE);
3103:                    child2 = child2.getNext();
3104:                }
3105:
3106:                cfw.addALoad(contextLocal);
3107:                cfw.addALoad(variableObjectLocal);
3108:                addScriptRuntimeInvoke("newObjectLiteral",
3109:                        "([Ljava/lang/Object;" + "[Ljava/lang/Object;" + "[I"
3110:                                + "Lorg/mozilla/javascript/Context;"
3111:                                + "Lorg/mozilla/javascript/Scriptable;"
3112:                                + ")Lorg/mozilla/javascript/Scriptable;");
3113:            }
3114:
3115:            private void visitSpecialCall(Node node, int type, int specialType,
3116:                    Node child) {
3117:                cfw.addALoad(contextLocal);
3118:
3119:                if (type == Token.NEW) {
3120:                    generateExpression(child, node);
3121:                    // stack: ... cx functionObj
3122:                } else {
3123:                    generateFunctionAndThisObj(child, node);
3124:                    // stack: ... cx functionObj thisObj
3125:                }
3126:                child = child.getNext();
3127:
3128:                generateCallArgArray(node, child, false);
3129:
3130:                String methodName;
3131:                String callSignature;
3132:
3133:                if (type == Token.NEW) {
3134:                    methodName = "newObjectSpecial";
3135:                    callSignature = "(Lorg/mozilla/javascript/Context;"
3136:                            + "Ljava/lang/Object;" + "[Ljava/lang/Object;"
3137:                            + "Lorg/mozilla/javascript/Scriptable;"
3138:                            + "Lorg/mozilla/javascript/Scriptable;" + "I" // call type
3139:                            + ")Ljava/lang/Object;";
3140:                    cfw.addALoad(variableObjectLocal);
3141:                    cfw.addALoad(this ObjLocal);
3142:                    cfw.addPush(specialType);
3143:                } else {
3144:                    methodName = "callSpecial";
3145:                    callSignature = "(Lorg/mozilla/javascript/Context;"
3146:                            + "Lorg/mozilla/javascript/Callable;"
3147:                            + "Lorg/mozilla/javascript/Scriptable;"
3148:                            + "[Ljava/lang/Object;"
3149:                            + "Lorg/mozilla/javascript/Scriptable;"
3150:                            + "Lorg/mozilla/javascript/Scriptable;" + "I" // call type
3151:                            + "Ljava/lang/String;I" // filename, linenumber
3152:                            + ")Ljava/lang/Object;";
3153:                    cfw.addALoad(variableObjectLocal);
3154:                    cfw.addALoad(this ObjLocal);
3155:                    cfw.addPush(specialType);
3156:                    String sourceName = scriptOrFn.getSourceName();
3157:                    cfw.addPush(sourceName == null ? "" : sourceName);
3158:                    cfw.addPush(itsLineNumber);
3159:                }
3160:
3161:                addOptRuntimeInvoke(methodName, callSignature);
3162:            }
3163:
3164:            private void visitStandardCall(Node node, Node child) {
3165:                if (node.getType() != Token.CALL)
3166:                    throw Codegen.badTree();
3167:
3168:                Node firstArgChild = child.getNext();
3169:                int childType = child.getType();
3170:
3171:                String methodName;
3172:                String signature;
3173:
3174:                if (firstArgChild == null) {
3175:                    if (childType == Token.NAME) {
3176:                        // name() call
3177:                        String name = child.getString();
3178:                        cfw.addPush(name);
3179:                        methodName = "callName0";
3180:                        signature = "(Ljava/lang/String;"
3181:                                + "Lorg/mozilla/javascript/Context;"
3182:                                + "Lorg/mozilla/javascript/Scriptable;"
3183:                                + ")Ljava/lang/Object;";
3184:                    } else if (childType == Token.GETPROP) {
3185:                        // x.name() call
3186:                        Node propTarget = child.getFirstChild();
3187:                        generateExpression(propTarget, node);
3188:                        Node id = propTarget.getNext();
3189:                        String property = id.getString();
3190:                        cfw.addPush(property);
3191:                        methodName = "callProp0";
3192:                        signature = "(Ljava/lang/Object;"
3193:                                + "Ljava/lang/String;"
3194:                                + "Lorg/mozilla/javascript/Context;"
3195:                                + "Lorg/mozilla/javascript/Scriptable;"
3196:                                + ")Ljava/lang/Object;";
3197:                    } else if (childType == Token.GETPROPNOWARN) {
3198:                        throw Kit.codeBug();
3199:                    } else {
3200:                        generateFunctionAndThisObj(child, node);
3201:                        methodName = "call0";
3202:                        signature = "(Lorg/mozilla/javascript/Callable;"
3203:                                + "Lorg/mozilla/javascript/Scriptable;"
3204:                                + "Lorg/mozilla/javascript/Context;"
3205:                                + "Lorg/mozilla/javascript/Scriptable;"
3206:                                + ")Ljava/lang/Object;";
3207:                    }
3208:
3209:                } else if (childType == Token.NAME) {
3210:                    // XXX: this optimization is only possible if name
3211:                    // resolution
3212:                    // is not affected by arguments evaluation and currently
3213:                    // there are no checks for it
3214:                    String name = child.getString();
3215:                    generateCallArgArray(node, firstArgChild, false);
3216:                    cfw.addPush(name);
3217:                    methodName = "callName";
3218:                    signature = "([Ljava/lang/Object;" + "Ljava/lang/String;"
3219:                            + "Lorg/mozilla/javascript/Context;"
3220:                            + "Lorg/mozilla/javascript/Scriptable;"
3221:                            + ")Ljava/lang/Object;";
3222:                } else {
3223:                    int argCount = 0;
3224:                    for (Node arg = firstArgChild; arg != null; arg = arg
3225:                            .getNext()) {
3226:                        ++argCount;
3227:                    }
3228:                    generateFunctionAndThisObj(child, node);
3229:                    // stack: ... functionObj thisObj
3230:                    if (argCount == 1) {
3231:                        generateExpression(firstArgChild, node);
3232:                        methodName = "call1";
3233:                        signature = "(Lorg/mozilla/javascript/Callable;"
3234:                                + "Lorg/mozilla/javascript/Scriptable;"
3235:                                + "Ljava/lang/Object;"
3236:                                + "Lorg/mozilla/javascript/Context;"
3237:                                + "Lorg/mozilla/javascript/Scriptable;"
3238:                                + ")Ljava/lang/Object;";
3239:                    } else if (argCount == 2) {
3240:                        generateExpression(firstArgChild, node);
3241:                        generateExpression(firstArgChild.getNext(), node);
3242:                        methodName = "call2";
3243:                        signature = "(Lorg/mozilla/javascript/Callable;"
3244:                                + "Lorg/mozilla/javascript/Scriptable;"
3245:                                + "Ljava/lang/Object;" + "Ljava/lang/Object;"
3246:                                + "Lorg/mozilla/javascript/Context;"
3247:                                + "Lorg/mozilla/javascript/Scriptable;"
3248:                                + ")Ljava/lang/Object;";
3249:                    } else {
3250:                        generateCallArgArray(node, firstArgChild, false);
3251:                        methodName = "callN";
3252:                        signature = "(Lorg/mozilla/javascript/Callable;"
3253:                                + "Lorg/mozilla/javascript/Scriptable;"
3254:                                + "[Ljava/lang/Object;"
3255:                                + "Lorg/mozilla/javascript/Context;"
3256:                                + "Lorg/mozilla/javascript/Scriptable;"
3257:                                + ")Ljava/lang/Object;";
3258:                    }
3259:                }
3260:
3261:                cfw.addALoad(contextLocal);
3262:                cfw.addALoad(variableObjectLocal);
3263:                addOptRuntimeInvoke(methodName, signature);
3264:            }
3265:
3266:            private void visitStandardNew(Node node, Node child) {
3267:                if (node.getType() != Token.NEW)
3268:                    throw Codegen.badTree();
3269:
3270:                Node firstArgChild = child.getNext();
3271:
3272:                generateExpression(child, node);
3273:                // stack: ... functionObj
3274:                cfw.addALoad(contextLocal);
3275:                cfw.addALoad(variableObjectLocal);
3276:                // stack: ... functionObj cx scope
3277:                generateCallArgArray(node, firstArgChild, false);
3278:                addScriptRuntimeInvoke("newObject", "(Ljava/lang/Object;"
3279:                        + "Lorg/mozilla/javascript/Context;"
3280:                        + "Lorg/mozilla/javascript/Scriptable;"
3281:                        + "[Ljava/lang/Object;"
3282:                        + ")Lorg/mozilla/javascript/Scriptable;");
3283:            }
3284:
3285:            private void visitOptimizedCall(Node node, OptFunctionNode target,
3286:                    int type, Node child) {
3287:                Node firstArgChild = child.getNext();
3288:
3289:                short this ObjLocal = 0;
3290:                if (type == Token.NEW) {
3291:                    generateExpression(child, node);
3292:                } else {
3293:                    generateFunctionAndThisObj(child, node);
3294:                    this ObjLocal = getNewWordLocal();
3295:                    cfw.addAStore(this ObjLocal);
3296:                }
3297:                // stack: ... functionObj
3298:
3299:                int beyond = cfw.acquireLabel();
3300:
3301:                int directTargetIndex = target.getDirectTargetIndex();
3302:                if (isTopLevel) {
3303:                    cfw.add(ByteCode.ALOAD_0);
3304:                } else {
3305:                    cfw.add(ByteCode.ALOAD_0);
3306:                    cfw.add(ByteCode.GETFIELD, codegen.mainClassName,
3307:                            Codegen.DIRECT_CALL_PARENT_FIELD,
3308:                            codegen.mainClassSignature);
3309:                }
3310:                cfw.add(ByteCode.GETFIELD, codegen.mainClassName, Codegen
3311:                        .getDirectTargetFieldName(directTargetIndex),
3312:                        codegen.mainClassSignature);
3313:
3314:                cfw.add(ByteCode.DUP2);
3315:                // stack: ... functionObj directFunct functionObj directFunct
3316:
3317:                int regularCall = cfw.acquireLabel();
3318:                cfw.add(ByteCode.IF_ACMPNE, regularCall);
3319:
3320:                // stack: ... functionObj directFunct
3321:                short stackHeight = cfw.getStackTop();
3322:                cfw.add(ByteCode.SWAP);
3323:                cfw.add(ByteCode.POP);
3324:                // stack: ... directFunct
3325:                if (compilerEnv.isUseDynamicScope()) {
3326:                    cfw.addALoad(contextLocal);
3327:                    cfw.addALoad(variableObjectLocal);
3328:                } else {
3329:                    cfw.add(ByteCode.DUP);
3330:                    // stack: ... directFunct directFunct
3331:                    cfw.addInvoke(ByteCode.INVOKEINTERFACE,
3332:                            "org/mozilla/javascript/Scriptable",
3333:                            "getParentScope",
3334:                            "()Lorg/mozilla/javascript/Scriptable;");
3335:                    // stack: ... directFunct scope
3336:                    cfw.addALoad(contextLocal);
3337:                    // stack: ... directFunct scope cx
3338:                    cfw.add(ByteCode.SWAP);
3339:                }
3340:                // stack: ... directFunc cx scope
3341:
3342:                if (type == Token.NEW) {
3343:                    cfw.add(ByteCode.ACONST_NULL);
3344:                } else {
3345:                    cfw.addALoad(this ObjLocal);
3346:                }
3347:                // stack: ... directFunc cx scope thisObj
3348:                /*
3349:                 Remember that directCall parameters are paired in 1 aReg and 1 dReg
3350:                 If the argument is an incoming arg, just pass the orginal pair thru.
3351:                 Else, if the argument is known to be typed 'Number', pass Void.TYPE
3352:                 in the aReg and the number is the dReg
3353:                 Else pass the JS object in the aReg and 0.0 in the dReg.
3354:                 */
3355:                Node argChild = firstArgChild;
3356:                while (argChild != null) {
3357:                    int dcp_register = nodeIsDirectCallParameter(argChild);
3358:                    if (dcp_register >= 0) {
3359:                        cfw.addALoad(dcp_register);
3360:                        cfw.addDLoad(dcp_register + 1);
3361:                    } else if (argChild.getIntProp(Node.ISNUMBER_PROP, -1) == Node.BOTH) {
3362:                        cfw.add(ByteCode.GETSTATIC, "java/lang/Void", "TYPE",
3363:                                "Ljava/lang/Class;");
3364:                        generateExpression(argChild, node);
3365:                    } else {
3366:                        generateExpression(argChild, node);
3367:                        cfw.addPush(0.0);
3368:                    }
3369:                    argChild = argChild.getNext();
3370:                }
3371:
3372:                cfw.add(ByteCode.GETSTATIC,
3373:                        "org/mozilla/javascript/ScriptRuntime", "emptyArgs",
3374:                        "[Ljava/lang/Object;");
3375:                cfw.addInvoke(ByteCode.INVOKESTATIC, codegen.mainClassName,
3376:                        (type == Token.NEW) ? codegen
3377:                                .getDirectCtorName(target.fnode) : codegen
3378:                                .getBodyMethodName(target.fnode), codegen
3379:                                .getBodyMethodSignature(target.fnode));
3380:
3381:                cfw.add(ByteCode.GOTO, beyond);
3382:
3383:                cfw.markLabel(regularCall, stackHeight);
3384:                // stack: ... functionObj directFunct
3385:                cfw.add(ByteCode.POP);
3386:                cfw.addALoad(contextLocal);
3387:                cfw.addALoad(variableObjectLocal);
3388:                // stack: ... functionObj cx scope
3389:                if (type != Token.NEW) {
3390:                    cfw.addALoad(this ObjLocal);
3391:                    releaseWordLocal(this ObjLocal);
3392:                    // stack: ... functionObj cx scope thisObj
3393:                }
3394:                // XXX: this will generate code for the child array the second time,
3395:                // so expression code generation better not to alter tree structure...
3396:                generateCallArgArray(node, firstArgChild, true);
3397:
3398:                if (type == Token.NEW) {
3399:                    addScriptRuntimeInvoke("newObject", "(Ljava/lang/Object;"
3400:                            + "Lorg/mozilla/javascript/Context;"
3401:                            + "Lorg/mozilla/javascript/Scriptable;"
3402:                            + "[Ljava/lang/Object;"
3403:                            + ")Lorg/mozilla/javascript/Scriptable;");
3404:                } else {
3405:                    cfw.addInvoke(ByteCode.INVOKEINTERFACE,
3406:                            "org/mozilla/javascript/Callable", "call",
3407:                            "(Lorg/mozilla/javascript/Context;"
3408:                                    + "Lorg/mozilla/javascript/Scriptable;"
3409:                                    + "Lorg/mozilla/javascript/Scriptable;"
3410:                                    + "[Ljava/lang/Object;"
3411:                                    + ")Ljava/lang/Object;");
3412:                }
3413:
3414:                cfw.markLabel(beyond);
3415:            }
3416:
3417:            private void generateCallArgArray(Node node, Node argChild,
3418:                    boolean directCall) {
3419:                int argCount = 0;
3420:                for (Node child = argChild; child != null; child = child
3421:                        .getNext()) {
3422:                    ++argCount;
3423:                }
3424:                // load array object to set arguments
3425:                if (argCount == 1 && itsOneArgArray >= 0) {
3426:                    cfw.addALoad(itsOneArgArray);
3427:                } else {
3428:                    addNewObjectArray(argCount);
3429:                }
3430:                // Copy arguments into it
3431:                for (int i = 0; i != argCount; ++i) {
3432:                    // If we are compiling a generator an argument could be the result
3433:                    // of a yield. In that case we will have an immediate on the stack
3434:                    // which we need to avoid
3435:                    if (!isGenerator) {
3436:                        cfw.add(ByteCode.DUP);
3437:                        cfw.addPush(i);
3438:                    }
3439:
3440:                    if (!directCall) {
3441:                        generateExpression(argChild, node);
3442:                    } else {
3443:                        // If this has also been a directCall sequence, the Number
3444:                        // flag will have remained set for any parameter so that
3445:                        // the values could be copied directly into the outgoing
3446:                        // args. Here we want to force it to be treated as not in
3447:                        // a Number context, so we set the flag off.
3448:                        int dcp_register = nodeIsDirectCallParameter(argChild);
3449:                        if (dcp_register >= 0) {
3450:                            dcpLoadAsObject(dcp_register);
3451:                        } else {
3452:                            generateExpression(argChild, node);
3453:                            int childNumberFlag = argChild.getIntProp(
3454:                                    Node.ISNUMBER_PROP, -1);
3455:                            if (childNumberFlag == Node.BOTH) {
3456:                                addDoubleWrap();
3457:                            }
3458:                        }
3459:                    }
3460:
3461:                    // When compiling generators, any argument to a method may be a
3462:                    // yield expression. Hence we compile the argument first and then
3463:                    // load the argument index and assign the value to the args array.
3464:                    if (isGenerator) {
3465:                        short tempLocal = getNewWordLocal();
3466:                        cfw.addAStore(tempLocal);
3467:                        cfw.add(ByteCode.CHECKCAST, "[Ljava/lang/Object;");
3468:                        cfw.add(ByteCode.DUP);
3469:                        cfw.addPush(i);
3470:                        cfw.addALoad(tempLocal);
3471:                        releaseWordLocal(tempLocal);
3472:                    }
3473:
3474:                    cfw.add(ByteCode.AASTORE);
3475:
3476:                    argChild = argChild.getNext();
3477:                }
3478:            }
3479:
3480:            private void generateFunctionAndThisObj(Node node, Node parent) {
3481:                // Place on stack (function object, function this) pair
3482:                int type = node.getType();
3483:                switch (node.getType()) {
3484:                case Token.GETPROPNOWARN:
3485:                    throw Kit.codeBug();
3486:
3487:                case Token.GETPROP:
3488:                case Token.GETELEM: {
3489:                    Node target = node.getFirstChild();
3490:                    generateExpression(target, node);
3491:                    Node id = target.getNext();
3492:                    if (type == Token.GETPROP) {
3493:                        String property = id.getString();
3494:                        cfw.addPush(property);
3495:                        cfw.addALoad(contextLocal);
3496:                        addScriptRuntimeInvoke("getPropFunctionAndThis",
3497:                                "(Ljava/lang/Object;" + "Ljava/lang/String;"
3498:                                        + "Lorg/mozilla/javascript/Context;"
3499:                                        + ")Lorg/mozilla/javascript/Callable;");
3500:                    } else {
3501:                        // Optimizer do not optimize this case for now
3502:                        if (node.getIntProp(Node.ISNUMBER_PROP, -1) != -1)
3503:                            throw Codegen.badTree();
3504:                        generateExpression(id, node); // id
3505:                        cfw.addALoad(contextLocal);
3506:                        addScriptRuntimeInvoke("getElemFunctionAndThis",
3507:                                "(Ljava/lang/Object;" + "Ljava/lang/Object;"
3508:                                        + "Lorg/mozilla/javascript/Context;"
3509:                                        + ")Lorg/mozilla/javascript/Callable;");
3510:                    }
3511:                    break;
3512:                }
3513:
3514:                case Token.NAME: {
3515:                    String name = node.getString();
3516:                    cfw.addPush(name);
3517:                    cfw.addALoad(contextLocal);
3518:                    cfw.addALoad(variableObjectLocal);
3519:                    addScriptRuntimeInvoke("getNameFunctionAndThis",
3520:                            "(Ljava/lang/String;"
3521:                                    + "Lorg/mozilla/javascript/Context;"
3522:                                    + "Lorg/mozilla/javascript/Scriptable;"
3523:                                    + ")Lorg/mozilla/javascript/Callable;");
3524:                    break;
3525:                }
3526:
3527:                default: // including GETVAR
3528:                    generateExpression(node, parent);
3529:                    cfw.addALoad(contextLocal);
3530:                    addScriptRuntimeInvoke("getValueFunctionAndThis",
3531:                            "(Ljava/lang/Object;"
3532:                                    + "Lorg/mozilla/javascript/Context;"
3533:                                    + ")Lorg/mozilla/javascript/Callable;");
3534:                    break;
3535:                }
3536:                // Get thisObj prepared by get(Name|Prop|Elem|Value)FunctionAndThis
3537:                cfw.addALoad(contextLocal);
3538:                addScriptRuntimeInvoke("lastStoredScriptable",
3539:                        "(Lorg/mozilla/javascript/Context;"
3540:                                + ")Lorg/mozilla/javascript/Scriptable;");
3541:            }
3542:
3543:            private void updateLineNumber(Node node) {
3544:                itsLineNumber = node.getLineno();
3545:                if (itsLineNumber == -1)
3546:                    return;
3547:                cfw.addLineNumberEntry((short) itsLineNumber);
3548:            }
3549:
3550:            private void visitTryCatchFinally(Node.Jump node, Node child) {
3551:                /* Save the variable object, in case there are with statements
3552:                 * enclosed by the try block and we catch some exception.
3553:                 * We'll restore it for the catch block so that catch block
3554:                 * statements get the right scope.
3555:                 */
3556:
3557:                // OPT we only need to do this if there are enclosed WITH
3558:                // statements; could statically check and omit this if there aren't any.
3559:                // XXX OPT Maybe instead do syntactic transforms to associate
3560:                // each 'with' with a try/finally block that does the exitwith.
3561:                short savedVariableObject = getNewWordLocal();
3562:                cfw.addALoad(variableObjectLocal);
3563:                cfw.addAStore(savedVariableObject);
3564:
3565:                /*
3566:                 * Generate the code for the tree; most of the work is done in IRFactory
3567:                 * and NodeTransformer;  Codegen just adds the java handlers for the
3568:                 * javascript catch and finally clauses.  */
3569:
3570:                int startLabel = cfw.acquireLabel();
3571:                cfw.markLabel(startLabel, (short) 0);
3572:
3573:                Node catchTarget = node.target;
3574:                Node finallyTarget = node.getFinally();
3575:
3576:                // create a table for the equivalent of JSR returns
3577:                if (isGenerator && finallyTarget != null) {
3578:                    FinallyReturnPoint ret = new FinallyReturnPoint();
3579:                    if (finallys == null) {
3580:                        finallys = new Hashtable();
3581:                    }
3582:                    // add the finally target to hashtable
3583:                    finallys.put(finallyTarget, ret);
3584:                    // add the finally node as well to the hash table
3585:                    finallys.put(finallyTarget.getNext(), ret);
3586:                }
3587:
3588:                while (child != null) {
3589:                    generateStatement(child);
3590:                    child = child.getNext();
3591:                }
3592:
3593:                // control flow skips the handlers
3594:                int realEnd = cfw.acquireLabel();
3595:                cfw.add(ByteCode.GOTO, realEnd);
3596:
3597:                int exceptionLocal = getLocalBlockRegister(node);
3598:                // javascript handler; unwrap exception and GOTO to javascript
3599:                // catch area.
3600:                if (catchTarget != null) {
3601:                    // get the label to goto
3602:                    int catchLabel = catchTarget.labelId();
3603:
3604:                    generateCatchBlock(JAVASCRIPT_EXCEPTION,
3605:                            savedVariableObject, catchLabel, startLabel,
3606:                            exceptionLocal);
3607:                    /*
3608:                     * catch WrappedExceptions, see if they are wrapped
3609:                     * JavaScriptExceptions. Otherwise, rethrow.
3610:                     */
3611:                    generateCatchBlock(EVALUATOR_EXCEPTION,
3612:                            savedVariableObject, catchLabel, startLabel,
3613:                            exceptionLocal);
3614:
3615:                    /*
3616:                        we also need to catch EcmaErrors and feed the
3617:                        associated error object to the handler
3618:                     */
3619:                    generateCatchBlock(ECMAERROR_EXCEPTION,
3620:                            savedVariableObject, catchLabel, startLabel,
3621:                            exceptionLocal);
3622:
3623:                    Context cx = Context.getCurrentContext();
3624:                    if (cx != null
3625:                            && cx
3626:                                    .hasFeature(Context.FEATURE_ENHANCED_JAVA_ACCESS)) {
3627:                        generateCatchBlock(THROWABLE_EXCEPTION,
3628:                                savedVariableObject, catchLabel, startLabel,
3629:                                exceptionLocal);
3630:                    }
3631:                }
3632:
3633:                // finally handler; catch all exceptions, store to a local; JSR to
3634:                // the finally, then re-throw.
3635:                if (finallyTarget != null) {
3636:                    int finallyHandler = cfw.acquireLabel();
3637:                    cfw.markHandler(finallyHandler);
3638:                    cfw.addAStore(exceptionLocal);
3639:
3640:                    // reset the variable object local
3641:                    cfw.addALoad(savedVariableObject);
3642:                    cfw.addAStore(variableObjectLocal);
3643:
3644:                    // get the label to JSR to
3645:                    int finallyLabel = finallyTarget.labelId();
3646:                    if (isGenerator)
3647:                        addGotoWithReturn(finallyTarget);
3648:                    else
3649:                        cfw.add(ByteCode.JSR, finallyLabel);
3650:
3651:                    // rethrow
3652:                    cfw.addALoad(exceptionLocal);
3653:                    if (isGenerator)
3654:                        cfw.add(ByteCode.CHECKCAST, "java/lang/Throwable");
3655:                    cfw.add(ByteCode.ATHROW);
3656:
3657:                    // mark the handler
3658:                    cfw.addExceptionHandler(startLabel, finallyLabel,
3659:                            finallyHandler, null); // catch any
3660:                }
3661:                releaseWordLocal(savedVariableObject);
3662:                cfw.markLabel(realEnd);
3663:            }
3664:
3665:            private static final int JAVASCRIPT_EXCEPTION = 0;
3666:            private static final int EVALUATOR_EXCEPTION = 1;
3667:            private static final int ECMAERROR_EXCEPTION = 2;
3668:            private static final int THROWABLE_EXCEPTION = 3;
3669:
3670:            private void generateCatchBlock(int exceptionType,
3671:                    short savedVariableObject, int catchLabel, int startLabel,
3672:                    int exceptionLocal) {
3673:                int handler = cfw.acquireLabel();
3674:                cfw.markHandler(handler);
3675:
3676:                // MS JVM gets cranky if the exception object is left on the stack
3677:                cfw.addAStore(exceptionLocal);
3678:
3679:                // reset the variable object local
3680:                cfw.addALoad(savedVariableObject);
3681:                cfw.addAStore(variableObjectLocal);
3682:
3683:                String exceptionName;
3684:                if (exceptionType == JAVASCRIPT_EXCEPTION) {
3685:                    exceptionName = "org/mozilla/javascript/JavaScriptException";
3686:                } else if (exceptionType == EVALUATOR_EXCEPTION) {
3687:                    exceptionName = "org/mozilla/javascript/EvaluatorException";
3688:                } else if (exceptionType == ECMAERROR_EXCEPTION) {
3689:                    exceptionName = "org/mozilla/javascript/EcmaError";
3690:                } else if (exceptionType == THROWABLE_EXCEPTION) {
3691:                    exceptionName = "java/lang/Throwable";
3692:                } else {
3693:                    throw Kit.codeBug();
3694:                }
3695:
3696:                // mark the handler
3697:                cfw.addExceptionHandler(startLabel, catchLabel, handler,
3698:                        exceptionName);
3699:
3700:                cfw.add(ByteCode.GOTO, catchLabel);
3701:            }
3702:
3703:            private boolean generateSaveLocals(Node node) {
3704:                int count = 0;
3705:                for (int i = 0; i < firstFreeLocal; i++) {
3706:                    if (locals[i] != 0)
3707:                        count++;
3708:                }
3709:
3710:                if (count == 0) {
3711:                    ((FunctionNode) scriptOrFn).addLiveLocals(node, null);
3712:                    return false;
3713:                }
3714:
3715:                // calculate the max locals
3716:                maxLocals = maxLocals > count ? maxLocals : count;
3717:
3718:                // create a locals list
3719:                int[] ls = new int[count];
3720:                int s = 0;
3721:                for (int i = 0; i < firstFreeLocal; i++) {
3722:                    if (locals[i] != 0) {
3723:                        ls[s] = i;
3724:                        s++;
3725:                    }
3726:                }
3727:
3728:                // save the locals
3729:                ((FunctionNode) scriptOrFn).addLiveLocals(node, ls);
3730:
3731:                // save locals
3732:                generateGetGeneratorLocalsState();
3733:                for (int i = 0; i < count; i++) {
3734:                    cfw.add(ByteCode.DUP);
3735:                    cfw.addLoadConstant(i);
3736:                    cfw.addALoad(ls[i]);
3737:                    cfw.add(ByteCode.AASTORE);
3738:                }
3739:                // pop the array off the stack
3740:                cfw.add(ByteCode.POP);
3741:
3742:                return true;
3743:            }
3744:
3745:            private void visitSwitch(Node.Jump switchNode, Node child) {
3746:                // See comments in IRFactory.createSwitch() for description
3747:                // of SWITCH node
3748:
3749:                generateExpression(child, switchNode);
3750:                // save selector value
3751:                short selector = getNewWordLocal();
3752:                cfw.addAStore(selector);
3753:
3754:                for (Node.Jump caseNode = (Node.Jump) child.getNext(); caseNode != null; caseNode = (Node.Jump) caseNode
3755:                        .getNext()) {
3756:                    if (caseNode.getType() != Token.CASE)
3757:                        throw Codegen.badTree();
3758:                    Node test = caseNode.getFirstChild();
3759:                    generateExpression(test, caseNode);
3760:                    cfw.addALoad(selector);
3761:                    addScriptRuntimeInvoke("shallowEq", "(Ljava/lang/Object;"
3762:                            + "Ljava/lang/Object;" + ")Z");
3763:                    addGoto(caseNode.target, ByteCode.IFNE);
3764:                }
3765:                releaseWordLocal(selector);
3766:            }
3767:
3768:            private void visitTypeofname(Node node) {
3769:                if (hasVarsInRegs) {
3770:                    int varIndex = fnCurrent.fnode.getIndexForNameNode(node);
3771:                    if (varIndex >= 0) {
3772:                        if (fnCurrent.isNumberVar(varIndex)) {
3773:                            cfw.addPush("number");
3774:                        } else if (varIsDirectCallParameter(varIndex)) {
3775:                            int dcp_register = varRegisters[varIndex];
3776:                            cfw.addALoad(dcp_register);
3777:                            cfw.add(ByteCode.GETSTATIC, "java/lang/Void",
3778:                                    "TYPE", "Ljava/lang/Class;");
3779:                            int isNumberLabel = cfw.acquireLabel();
3780:                            cfw.add(ByteCode.IF_ACMPEQ, isNumberLabel);
3781:                            short stack = cfw.getStackTop();
3782:                            cfw.addALoad(dcp_register);
3783:                            addScriptRuntimeInvoke("typeof",
3784:                                    "(Ljava/lang/Object;"
3785:                                            + ")Ljava/lang/String;");
3786:                            int beyond = cfw.acquireLabel();
3787:                            cfw.add(ByteCode.GOTO, beyond);
3788:                            cfw.markLabel(isNumberLabel, stack);
3789:                            cfw.addPush("number");
3790:                            cfw.markLabel(beyond);
3791:                        } else {
3792:                            cfw.addALoad(varRegisters[varIndex]);
3793:                            addScriptRuntimeInvoke("typeof",
3794:                                    "(Ljava/lang/Object;"
3795:                                            + ")Ljava/lang/String;");
3796:                        }
3797:                        return;
3798:                    }
3799:                }
3800:                cfw.addALoad(variableObjectLocal);
3801:                cfw.addPush(node.getString());
3802:                addScriptRuntimeInvoke("typeofName",
3803:                        "(Lorg/mozilla/javascript/Scriptable;"
3804:                                + "Ljava/lang/String;" + ")Ljava/lang/String;");
3805:            }
3806:
3807:            /**
3808:             * Save the current code offset. This saved code offset is used to
3809:             * compute instruction counts in subsequent calls to
3810:             * {@link #addInstructionCount}.
3811:             */
3812:            private void saveCurrentCodeOffset() {
3813:                savedCodeOffset = cfw.getCurrentCodeOffset();
3814:            }
3815:
3816:            /**
3817:             * Generate calls to ScriptRuntime.addInstructionCount to keep track of
3818:             * executed instructions and call <code>observeInstructionCount()</code>
3819:             * if a threshold is exceeded.
3820:             */
3821:            private void addInstructionCount() {
3822:                int count = cfw.getCurrentCodeOffset() - savedCodeOffset;
3823:                if (count == 0)
3824:                    return;
3825:                cfw.addALoad(contextLocal);
3826:                cfw.addPush(count);
3827:                addScriptRuntimeInvoke("addInstructionCount",
3828:                        "(Lorg/mozilla/javascript/Context;" + "I)V");
3829:            }
3830:
3831:            private void visitIncDec(Node node) {
3832:                int incrDecrMask = node.getExistingIntProp(Node.INCRDECR_PROP);
3833:                Node child = node.getFirstChild();
3834:                switch (child.getType()) {
3835:                case Token.GETVAR:
3836:                    if (!hasVarsInRegs)
3837:                        Kit.codeBug();
3838:                    if (node.getIntProp(Node.ISNUMBER_PROP, -1) != -1) {
3839:                        boolean post = ((incrDecrMask & Node.POST_FLAG) != 0);
3840:                        int varIndex = fnCurrent.getVarIndex(child);
3841:                        short reg = varRegisters[varIndex];
3842:                        int offset = varIsDirectCallParameter(varIndex) ? 1 : 0;
3843:                        cfw.addDLoad(reg + offset);
3844:                        if (post) {
3845:                            cfw.add(ByteCode.DUP2);
3846:                        }
3847:                        cfw.addPush(1.0);
3848:                        if ((incrDecrMask & Node.DECR_FLAG) == 0) {
3849:                            cfw.add(ByteCode.DADD);
3850:                        } else {
3851:                            cfw.add(ByteCode.DSUB);
3852:                        }
3853:                        if (!post) {
3854:                            cfw.add(ByteCode.DUP2);
3855:                        }
3856:                        cfw.addDStore(reg + offset);
3857:                    } else {
3858:                        boolean post = ((incrDecrMask & Node.POST_FLAG) != 0);
3859:                        int varIndex = fnCurrent.getVarIndex(child);
3860:                        short reg = varRegisters[varIndex];
3861:                        cfw.addALoad(reg);
3862:                        if (post) {
3863:                            cfw.add(ByteCode.DUP);
3864:                        }
3865:                        addObjectToDouble();
3866:                        cfw.addPush(1.0);
3867:                        if ((incrDecrMask & Node.DECR_FLAG) == 0) {
3868:                            cfw.add(ByteCode.DADD);
3869:                        } else {
3870:                            cfw.add(ByteCode.DSUB);
3871:                        }
3872:                        addDoubleWrap();
3873:                        if (!post) {
3874:                            cfw.add(ByteCode.DUP);
3875:                        }
3876:                        cfw.addAStore(reg);
3877:                        break;
3878:                    }
3879:                    break;
3880:                case Token.NAME:
3881:                    cfw.addALoad(variableObjectLocal);
3882:                    cfw.addPush(child.getString()); // push name
3883:                    cfw.addALoad(contextLocal);
3884:                    cfw.addPush(incrDecrMask);
3885:                    addScriptRuntimeInvoke("nameIncrDecr",
3886:                            "(Lorg/mozilla/javascript/Scriptable;"
3887:                                    + "Ljava/lang/String;"
3888:                                    + "Lorg/mozilla/javascript/Context;"
3889:                                    + "I)Ljava/lang/Object;");
3890:                    break;
3891:                case Token.GETPROPNOWARN:
3892:                    throw Kit.codeBug();
3893:                case Token.GETPROP: {
3894:                    Node getPropChild = child.getFirstChild();
3895:                    generateExpression(getPropChild, node);
3896:                    generateExpression(getPropChild.getNext(), node);
3897:                    cfw.addALoad(contextLocal);
3898:                    cfw.addPush(incrDecrMask);
3899:                    addScriptRuntimeInvoke("propIncrDecr",
3900:                            "(Ljava/lang/Object;" + "Ljava/lang/String;"
3901:                                    + "Lorg/mozilla/javascript/Context;"
3902:                                    + "I)Ljava/lang/Object;");
3903:                    break;
3904:                }
3905:                case Token.GETELEM: {
3906:                    Node elemChild = child.getFirstChild();
3907:                    generateExpression(elemChild, node);
3908:                    generateExpression(elemChild.getNext(), node);
3909:                    cfw.addALoad(contextLocal);
3910:                    cfw.addPush(incrDecrMask);
3911:                    if (elemChild.getNext().getIntProp(Node.ISNUMBER_PROP, -1) != -1) {
3912:                        addOptRuntimeInvoke("elemIncrDecr",
3913:                                "(Ljava/lang/Object;" + "D"
3914:                                        + "Lorg/mozilla/javascript/Context;"
3915:                                        + "I" + ")Ljava/lang/Object;");
3916:                    } else {
3917:                        addScriptRuntimeInvoke("elemIncrDecr",
3918:                                "(Ljava/lang/Object;" + "Ljava/lang/Object;"
3919:                                        + "Lorg/mozilla/javascript/Context;"
3920:                                        + "I" + ")Ljava/lang/Object;");
3921:                    }
3922:                    break;
3923:                }
3924:                case Token.GET_REF: {
3925:                    Node refChild = child.getFirstChild();
3926:                    generateExpression(refChild, node);
3927:                    cfw.addALoad(contextLocal);
3928:                    cfw.addPush(incrDecrMask);
3929:                    addScriptRuntimeInvoke("refIncrDecr",
3930:                            "(Lorg/mozilla/javascript/Ref;"
3931:                                    + "Lorg/mozilla/javascript/Context;"
3932:                                    + "I)Ljava/lang/Object;");
3933:                    break;
3934:                }
3935:                default:
3936:                    Codegen.badTree();
3937:                }
3938:            }
3939:
3940:            private static boolean isArithmeticNode(Node node) {
3941:                int type = node.getType();
3942:                return (type == Token.SUB) || (type == Token.MOD)
3943:                        || (type == Token.DIV) || (type == Token.MUL);
3944:            }
3945:
3946:            private void visitArithmetic(Node node, int opCode, Node child,
3947:                    Node parent) {
3948:                int childNumberFlag = node.getIntProp(Node.ISNUMBER_PROP, -1);
3949:                if (childNumberFlag != -1) {
3950:                    generateExpression(child, node);
3951:                    generateExpression(child.getNext(), node);
3952:                    cfw.add(opCode);
3953:                } else {
3954:                    boolean childOfArithmetic = isArithmeticNode(parent);
3955:                    generateExpression(child, node);
3956:                    if (!isArithmeticNode(child))
3957:                        addObjectToDouble();
3958:                    generateExpression(child.getNext(), node);
3959:                    if (!isArithmeticNode(child.getNext()))
3960:                        addObjectToDouble();
3961:                    cfw.add(opCode);
3962:                    if (!childOfArithmetic) {
3963:                        addDoubleWrap();
3964:                    }
3965:                }
3966:            }
3967:
3968:            private void visitBitOp(Node node, int type, Node child) {
3969:                int childNumberFlag = node.getIntProp(Node.ISNUMBER_PROP, -1);
3970:                generateExpression(child, node);
3971:
3972:                // special-case URSH; work with the target arg as a long, so
3973:                // that we can return a 32-bit unsigned value, and call
3974:                // toUint32 instead of toInt32.
3975:                if (type == Token.URSH) {
3976:                    addScriptRuntimeInvoke("toUint32", "(Ljava/lang/Object;)J");
3977:                    generateExpression(child.getNext(), node);
3978:                    addScriptRuntimeInvoke("toInt32", "(Ljava/lang/Object;)I");
3979:                    // Looks like we need to explicitly mask the shift to 5 bits -
3980:                    // LUSHR takes 6 bits.
3981:                    cfw.addPush(31);
3982:                    cfw.add(ByteCode.IAND);
3983:                    cfw.add(ByteCode.LUSHR);
3984:                    cfw.add(ByteCode.L2D);
3985:                    addDoubleWrap();
3986:                    return;
3987:                }
3988:                if (childNumberFlag == -1) {
3989:                    addScriptRuntimeInvoke("toInt32", "(Ljava/lang/Object;)I");
3990:                    generateExpression(child.getNext(), node);
3991:                    addScriptRuntimeInvoke("toInt32", "(Ljava/lang/Object;)I");
3992:                } else {
3993:                    addScriptRuntimeInvoke("toInt32", "(D)I");
3994:                    generateExpression(child.getNext(), node);
3995:                    addScriptRuntimeInvoke("toInt32", "(D)I");
3996:                }
3997:                switch (type) {
3998:                case Token.BITOR:
3999:                    cfw.add(ByteCode.IOR);
4000:                    break;
4001:                case Token.BITXOR:
4002:                    cfw.add(ByteCode.IXOR);
4003:                    break;
4004:                case Token.BITAND:
4005:                    cfw.add(ByteCode.IAND);
4006:                    break;
4007:                case Token.RSH:
4008:                    cfw.add(ByteCode.ISHR);
4009:                    break;
4010:                case Token.LSH:
4011:                    cfw.add(ByteCode.ISHL);
4012:                    break;
4013:                default:
4014:                    throw Codegen.badTree();
4015:                }
4016:                cfw.add(ByteCode.I2D);
4017:                if (childNumberFlag == -1) {
4018:                    addDoubleWrap();
4019:                }
4020:            }
4021:
4022:            private int nodeIsDirectCallParameter(Node node) {
4023:                if (node.getType() == Token.GETVAR && inDirectCallFunction
4024:                        && !itsForcedObjectParameters) {
4025:                    int varIndex = fnCurrent.getVarIndex(node);
4026:                    if (fnCurrent.isParameter(varIndex)) {
4027:                        return varRegisters[varIndex];
4028:                    }
4029:                }
4030:                return -1;
4031:            }
4032:
4033:            private boolean varIsDirectCallParameter(int varIndex) {
4034:                return fnCurrent.isParameter(varIndex) && inDirectCallFunction
4035:                        && !itsForcedObjectParameters;
4036:            }
4037:
4038:            private void genSimpleCompare(int type, int trueGOTO, int falseGOTO) {
4039:                if (trueGOTO == -1)
4040:                    throw Codegen.badTree();
4041:                switch (type) {
4042:                case Token.LE:
4043:                    cfw.add(ByteCode.DCMPG);
4044:                    cfw.add(ByteCode.IFLE, trueGOTO);
4045:                    break;
4046:                case Token.GE:
4047:                    cfw.add(ByteCode.DCMPL);
4048:                    cfw.add(ByteCode.IFGE, trueGOTO);
4049:                    break;
4050:                case Token.LT:
4051:                    cfw.add(ByteCode.DCMPG);
4052:                    cfw.add(ByteCode.IFLT, trueGOTO);
4053:                    break;
4054:                case Token.GT:
4055:                    cfw.add(ByteCode.DCMPL);
4056:                    cfw.add(ByteCode.IFGT, trueGOTO);
4057:                    break;
4058:                default:
4059:                    throw Codegen.badTree();
4060:
4061:                }
4062:                if (falseGOTO != -1)
4063:                    cfw.add(ByteCode.GOTO, falseGOTO);
4064:            }
4065:
4066:            private void visitIfJumpRelOp(Node node, Node child, int trueGOTO,
4067:                    int falseGOTO) {
4068:                if (trueGOTO == -1 || falseGOTO == -1)
4069:                    throw Codegen.badTree();
4070:                int type = node.getType();
4071:                Node rChild = child.getNext();
4072:                if (type == Token.INSTANCEOF || type == Token.IN) {
4073:                    generateExpression(child, node);
4074:                    generateExpression(rChild, node);
4075:                    cfw.addALoad(contextLocal);
4076:                    addScriptRuntimeInvoke(
4077:                            (type == Token.INSTANCEOF) ? "instanceOf" : "in",
4078:                            "(Ljava/lang/Object;" + "Ljava/lang/Object;"
4079:                                    + "Lorg/mozilla/javascript/Context;" + ")Z");
4080:                    cfw.add(ByteCode.IFNE, trueGOTO);
4081:                    cfw.add(ByteCode.GOTO, falseGOTO);
4082:                    return;
4083:                }
4084:                int childNumberFlag = node.getIntProp(Node.ISNUMBER_PROP, -1);
4085:                int left_dcp_register = nodeIsDirectCallParameter(child);
4086:                int right_dcp_register = nodeIsDirectCallParameter(rChild);
4087:                if (childNumberFlag != -1) {
4088:                    // Force numeric context on both parameters and optimize
4089:                    // direct call case as Optimizer currently does not handle it
4090:
4091:                    if (childNumberFlag != Node.RIGHT) {
4092:                        // Left already has number content
4093:                        generateExpression(child, node);
4094:                    } else if (left_dcp_register != -1) {
4095:                        dcpLoadAsNumber(left_dcp_register);
4096:                    } else {
4097:                        generateExpression(child, node);
4098:                        addObjectToDouble();
4099:                    }
4100:
4101:                    if (childNumberFlag != Node.LEFT) {
4102:                        // Right already has number content
4103:                        generateExpression(rChild, node);
4104:                    } else if (right_dcp_register != -1) {
4105:                        dcpLoadAsNumber(right_dcp_register);
4106:                    } else {
4107:                        generateExpression(rChild, node);
4108:                        addObjectToDouble();
4109:                    }
4110:
4111:                    genSimpleCompare(type, trueGOTO, falseGOTO);
4112:
4113:                } else {
4114:                    if (left_dcp_register != -1 && right_dcp_register != -1) {
4115:                        // Generate code to dynamically check for number content
4116:                        // if both operands are dcp
4117:                        short stack = cfw.getStackTop();
4118:                        int leftIsNotNumber = cfw.acquireLabel();
4119:                        cfw.addALoad(left_dcp_register);
4120:                        cfw.add(ByteCode.GETSTATIC, "java/lang/Void", "TYPE",
4121:                                "Ljava/lang/Class;");
4122:                        cfw.add(ByteCode.IF_ACMPNE, leftIsNotNumber);
4123:                        cfw.addDLoad(left_dcp_register + 1);
4124:                        dcpLoadAsNumber(right_dcp_register);
4125:                        genSimpleCompare(type, trueGOTO, falseGOTO);
4126:                        if (stack != cfw.getStackTop())
4127:                            throw Codegen.badTree();
4128:
4129:                        cfw.markLabel(leftIsNotNumber);
4130:                        int rightIsNotNumber = cfw.acquireLabel();
4131:                        cfw.addALoad(right_dcp_register);
4132:                        cfw.add(ByteCode.GETSTATIC, "java/lang/Void", "TYPE",
4133:                                "Ljava/lang/Class;");
4134:                        cfw.add(ByteCode.IF_ACMPNE, rightIsNotNumber);
4135:                        cfw.addALoad(left_dcp_register);
4136:                        addObjectToDouble();
4137:                        cfw.addDLoad(right_dcp_register + 1);
4138:                        genSimpleCompare(type, trueGOTO, falseGOTO);
4139:                        if (stack != cfw.getStackTop())
4140:                            throw Codegen.badTree();
4141:
4142:                        cfw.markLabel(rightIsNotNumber);
4143:                        // Load both register as objects to call generic cmp_*
4144:                        cfw.addALoad(left_dcp_register);
4145:                        cfw.addALoad(right_dcp_register);
4146:
4147:                    } else {
4148:                        generateExpression(child, node);
4149:                        generateExpression(rChild, node);
4150:                    }
4151:
4152:                    if (type == Token.GE || type == Token.GT) {
4153:                        cfw.add(ByteCode.SWAP);
4154:                    }
4155:                    String routine = ((type == Token.LT) || (type == Token.GT)) ? "cmp_LT"
4156:                            : "cmp_LE";
4157:                    addScriptRuntimeInvoke(routine, "(Ljava/lang/Object;"
4158:                            + "Ljava/lang/Object;" + ")Z");
4159:                    cfw.add(ByteCode.IFNE, trueGOTO);
4160:                    cfw.add(ByteCode.GOTO, falseGOTO);
4161:                }
4162:            }
4163:
4164:            private void visitIfJumpEqOp(Node node, Node child, int trueGOTO,
4165:                    int falseGOTO) {
4166:                if (trueGOTO == -1 || falseGOTO == -1)
4167:                    throw Codegen.badTree();
4168:
4169:                short stackInitial = cfw.getStackTop();
4170:                int type = node.getType();
4171:                Node rChild = child.getNext();
4172:
4173:                // Optimize if one of operands is null
4174:                if (child.getType() == Token.NULL
4175:                        || rChild.getType() == Token.NULL) {
4176:                    // eq is symmetric in this case
4177:                    if (child.getType() == Token.NULL) {
4178:                        child = rChild;
4179:                    }
4180:                    generateExpression(child, node);
4181:                    if (type == Token.SHEQ || type == Token.SHNE) {
4182:                        int testCode = (type == Token.SHEQ) ? ByteCode.IFNULL
4183:                                : ByteCode.IFNONNULL;
4184:                        cfw.add(testCode, trueGOTO);
4185:                    } else {
4186:                        if (type != Token.EQ) {
4187:                            // swap false/true targets for !=
4188:                            if (type != Token.NE)
4189:                                throw Codegen.badTree();
4190:                            int tmp = trueGOTO;
4191:                            trueGOTO = falseGOTO;
4192:                            falseGOTO = tmp;
4193:                        }
4194:                        cfw.add(ByteCode.DUP);
4195:                        int undefCheckLabel = cfw.acquireLabel();
4196:                        cfw.add(ByteCode.IFNONNULL, undefCheckLabel);
4197:                        short stack = cfw.getStackTop();
4198:                        cfw.add(ByteCode.POP);
4199:                        cfw.add(ByteCode.GOTO, trueGOTO);
4200:                        cfw.markLabel(undefCheckLabel, stack);
4201:                        Codegen.pushUndefined(cfw);
4202:                        cfw.add(ByteCode.IF_ACMPEQ, trueGOTO);
4203:                    }
4204:                    cfw.add(ByteCode.GOTO, falseGOTO);
4205:                } else {
4206:                    int child_dcp_register = nodeIsDirectCallParameter(child);
4207:                    if (child_dcp_register != -1
4208:                            && rChild.getType() == Token.TO_OBJECT) {
4209:                        Node convertChild = rChild.getFirstChild();
4210:                        if (convertChild.getType() == Token.NUMBER) {
4211:                            cfw.addALoad(child_dcp_register);
4212:                            cfw.add(ByteCode.GETSTATIC, "java/lang/Void",
4213:                                    "TYPE", "Ljava/lang/Class;");
4214:                            int notNumbersLabel = cfw.acquireLabel();
4215:                            cfw.add(ByteCode.IF_ACMPNE, notNumbersLabel);
4216:                            cfw.addDLoad(child_dcp_register + 1);
4217:                            cfw.addPush(convertChild.getDouble());
4218:                            cfw.add(ByteCode.DCMPL);
4219:                            if (type == Token.EQ)
4220:                                cfw.add(ByteCode.IFEQ, trueGOTO);
4221:                            else
4222:                                cfw.add(ByteCode.IFNE, trueGOTO);
4223:                            cfw.add(ByteCode.GOTO, falseGOTO);
4224:                            cfw.markLabel(notNumbersLabel);
4225:                            // fall thru into generic handling
4226:                        }
4227:                    }
4228:
4229:                    generateExpression(child, node);
4230:                    generateExpression(rChild, node);
4231:
4232:                    String name;
4233:                    int testCode;
4234:                    switch (type) {
4235:                    case Token.EQ:
4236:                        name = "eq";
4237:                        testCode = ByteCode.IFNE;
4238:                        break;
4239:                    case Token.NE:
4240:                        name = "eq";
4241:                        testCode = ByteCode.IFEQ;
4242:                        break;
4243:                    case Token.SHEQ:
4244:                        name = "shallowEq";
4245:                        testCode = ByteCode.IFNE;
4246:                        break;
4247:                    case Token.SHNE:
4248:                        name = "shallowEq";
4249:                        testCode = ByteCode.IFEQ;
4250:                        break;
4251:                    default:
4252:                        throw Codegen.badTree();
4253:                    }
4254:                    addScriptRuntimeInvoke(name, "(Ljava/lang/Object;"
4255:                            + "Ljava/lang/Object;" + ")Z");
4256:                    cfw.add(testCode, trueGOTO);
4257:                    cfw.add(ByteCode.GOTO, falseGOTO);
4258:                }
4259:                if (stackInitial != cfw.getStackTop())
4260:                    throw Codegen.badTree();
4261:            }
4262:
4263:            private void visitSetName(Node node, Node child) {
4264:                String name = node.getFirstChild().getString();
4265:                while (child != null) {
4266:                    generateExpression(child, node);
4267:                    child = child.getNext();
4268:                }
4269:                cfw.addALoad(contextLocal);
4270:                cfw.addALoad(variableObjectLocal);
4271:                cfw.addPush(name);
4272:                addScriptRuntimeInvoke("setName",
4273:                        "(Lorg/mozilla/javascript/Scriptable;"
4274:                                + "Ljava/lang/Object;"
4275:                                + "Lorg/mozilla/javascript/Context;"
4276:                                + "Lorg/mozilla/javascript/Scriptable;"
4277:                                + "Ljava/lang/String;" + ")Ljava/lang/Object;");
4278:            }
4279:
4280:            private void visitSetConst(Node node, Node child) {
4281:                String name = node.getFirstChild().getString();
4282:                while (child != null) {
4283:                    generateExpression(child, node);
4284:                    child = child.getNext();
4285:                }
4286:                cfw.addALoad(contextLocal);
4287:                cfw.addPush(name);
4288:                addScriptRuntimeInvoke("setConst",
4289:                        "(Lorg/mozilla/javascript/Scriptable;"
4290:                                + "Ljava/lang/Object;"
4291:                                + "Lorg/mozilla/javascript/Context;"
4292:                                + "Ljava/lang/String;" + ")Ljava/lang/Object;");
4293:            }
4294:
4295:            private void visitGetVar(Node node) {
4296:                if (!hasVarsInRegs)
4297:                    Kit.codeBug();
4298:                int varIndex = fnCurrent.getVarIndex(node);
4299:                short reg = varRegisters[varIndex];
4300:                if (varIsDirectCallParameter(varIndex)) {
4301:                    // Remember that here the isNumber flag means that we
4302:                    // want to use the incoming parameter in a Number
4303:                    // context, so test the object type and convert the
4304:                    //  value as necessary.
4305:                    if (node.getIntProp(Node.ISNUMBER_PROP, -1) != -1) {
4306:                        dcpLoadAsNumber(reg);
4307:                    } else {
4308:                        dcpLoadAsObject(reg);
4309:                    }
4310:                } else if (fnCurrent.isNumberVar(varIndex)) {
4311:                    cfw.addDLoad(reg);
4312:                } else {
4313:                    cfw.addALoad(reg);
4314:                }
4315:            }
4316:
4317:            private void visitSetVar(Node node, Node child, boolean needValue) {
4318:                if (!hasVarsInRegs)
4319:                    Kit.codeBug();
4320:                int varIndex = fnCurrent.getVarIndex(node);
4321:                generateExpression(child.getNext(), node);
4322:                boolean isNumber = (node.getIntProp(Node.ISNUMBER_PROP, -1) != -1);
4323:                short reg = varRegisters[varIndex];
4324:                boolean[] constDeclarations = fnCurrent.fnode
4325:                        .getParamAndVarConst();
4326:                if (constDeclarations[varIndex]) {
4327:                    if (!needValue) {
4328:                        if (isNumber)
4329:                            cfw.add(ByteCode.POP2);
4330:                        else
4331:                            cfw.add(ByteCode.POP);
4332:                    }
4333:                } else if (varIsDirectCallParameter(varIndex)) {
4334:                    if (isNumber) {
4335:                        if (needValue)
4336:                            cfw.add(ByteCode.DUP2);
4337:                        cfw.addALoad(reg);
4338:                        cfw.add(ByteCode.GETSTATIC, "java/lang/Void", "TYPE",
4339:                                "Ljava/lang/Class;");
4340:                        int isNumberLabel = cfw.acquireLabel();
4341:                        int beyond = cfw.acquireLabel();
4342:                        cfw.add(ByteCode.IF_ACMPEQ, isNumberLabel);
4343:                        short stack = cfw.getStackTop();
4344:                        addDoubleWrap();
4345:                        cfw.addAStore(reg);
4346:                        cfw.add(ByteCode.GOTO, beyond);
4347:                        cfw.markLabel(isNumberLabel, stack);
4348:                        cfw.addDStore(reg + 1);
4349:                        cfw.markLabel(beyond);
4350:                    } else {
4351:                        if (needValue)
4352:                            cfw.add(ByteCode.DUP);
4353:                        cfw.addAStore(reg);
4354:                    }
4355:                } else {
4356:                    boolean isNumberVar = fnCurrent.isNumberVar(varIndex);
4357:                    if (isNumber) {
4358:                        if (isNumberVar) {
4359:                            cfw.addDStore(reg);
4360:                            if (needValue)
4361:                                cfw.addDLoad(reg);
4362:                        } else {
4363:                            if (needValue)
4364:                                cfw.add(ByteCode.DUP2);
4365:                            // Cannot save number in variable since !isNumberVar,
4366:                            // so convert to object
4367:                            addDoubleWrap();
4368:                            cfw.addAStore(reg);
4369:                        }
4370:                    } else {
4371:                        if (isNumberVar)
4372:                            Kit.codeBug();
4373:                        cfw.addAStore(reg);
4374:                        if (needValue)
4375:                            cfw.addALoad(reg);
4376:                    }
4377:                }
4378:            }
4379:
4380:            private void visitSetConstVar(Node node, Node child,
4381:                    boolean needValue) {
4382:                if (!hasVarsInRegs)
4383:                    Kit.codeBug();
4384:                int varIndex = fnCurrent.getVarIndex(node);
4385:                generateExpression(child.getNext(), node);
4386:                boolean isNumber = (node.getIntProp(Node.ISNUMBER_PROP, -1) != -1);
4387:                short reg = varRegisters[varIndex];
4388:                int beyond = cfw.acquireLabel();
4389:                int noAssign = cfw.acquireLabel();
4390:                if (isNumber) {
4391:                    cfw.addILoad(reg + 2);
4392:                    cfw.add(ByteCode.IFNE, noAssign);
4393:                    short stack = cfw.getStackTop();
4394:                    cfw.addPush(1);
4395:                    cfw.addIStore(reg + 2);
4396:                    cfw.addDStore(reg);
4397:                    if (needValue) {
4398:                        cfw.addDLoad(reg);
4399:                        cfw.markLabel(noAssign, stack);
4400:                    } else {
4401:                        cfw.add(ByteCode.GOTO, beyond);
4402:                        cfw.markLabel(noAssign, stack);
4403:                        cfw.add(ByteCode.POP2);
4404:                    }
4405:                } else {
4406:                    cfw.addILoad(reg + 1);
4407:                    cfw.add(ByteCode.IFNE, noAssign);
4408:                    short stack = cfw.getStackTop();
4409:                    cfw.addPush(1);
4410:                    cfw.addIStore(reg + 1);
4411:                    cfw.addAStore(reg);
4412:                    if (needValue) {
4413:                        cfw.addALoad(reg);
4414:                        cfw.markLabel(noAssign, stack);
4415:                    } else {
4416:                        cfw.add(ByteCode.GOTO, beyond);
4417:                        cfw.markLabel(noAssign, stack);
4418:                        cfw.add(ByteCode.POP);
4419:                    }
4420:                }
4421:                cfw.markLabel(beyond);
4422:            }
4423:
4424:            private void visitGetProp(Node node, Node child) {
4425:                generateExpression(child, node); // object
4426:                Node nameChild = child.getNext();
4427:                generateExpression(nameChild, node); // the name
4428:                if (node.getType() == Token.GETPROPNOWARN) {
4429:                    cfw.addALoad(contextLocal);
4430:                    addScriptRuntimeInvoke("getObjectPropNoWarn",
4431:                            "(Ljava/lang/Object;" + "Ljava/lang/String;"
4432:                                    + "Lorg/mozilla/javascript/Context;"
4433:                                    + ")Ljava/lang/Object;");
4434:                    return;
4435:                }
4436:                /*
4437:                    for 'this.foo' we call getObjectProp(Scriptable...) which can
4438:                    skip some casting overhead.
4439:                 */
4440:                int childType = child.getType();
4441:                if (childType == Token.THIS
4442:                        && nameChild.getType() == Token.STRING) {
4443:                    cfw.addALoad(contextLocal);
4444:                    addScriptRuntimeInvoke("getObjectProp",
4445:                            "(Lorg/mozilla/javascript/Scriptable;"
4446:                                    + "Ljava/lang/String;"
4447:                                    + "Lorg/mozilla/javascript/Context;"
4448:                                    + ")Ljava/lang/Object;");
4449:                } else {
4450:                    cfw.addALoad(contextLocal);
4451:                    addScriptRuntimeInvoke("getObjectProp",
4452:                            "(Ljava/lang/Object;" + "Ljava/lang/String;"
4453:                                    + "Lorg/mozilla/javascript/Context;"
4454:                                    + ")Ljava/lang/Object;");
4455:                }
4456:            }
4457:
4458:            private void visitSetProp(int type, Node node, Node child) {
4459:                Node objectChild = child;
4460:                generateExpression(child, node);
4461:                child = child.getNext();
4462:                if (type == Token.SETPROP_OP) {
4463:                    cfw.add(ByteCode.DUP);
4464:                }
4465:                Node nameChild = child;
4466:                generateExpression(child, node);
4467:                child = child.getNext();
4468:                if (type == Token.SETPROP_OP) {
4469:                    // stack: ... object object name -> ... object name object name
4470:                    cfw.add(ByteCode.DUP_X1);
4471:                    //for 'this.foo += ...' we call thisGet which can skip some
4472:                    //casting overhead.
4473:                    if (objectChild.getType() == Token.THIS
4474:                            && nameChild.getType() == Token.STRING) {
4475:                        cfw.addALoad(contextLocal);
4476:                        addScriptRuntimeInvoke("getObjectProp",
4477:                                "(Lorg/mozilla/javascript/Scriptable;"
4478:                                        + "Ljava/lang/String;"
4479:                                        + "Lorg/mozilla/javascript/Context;"
4480:                                        + ")Ljava/lang/Object;");
4481:                    } else {
4482:                        cfw.addALoad(contextLocal);
4483:                        addScriptRuntimeInvoke("getObjectProp",
4484:                                "(Ljava/lang/Object;" + "Ljava/lang/String;"
4485:                                        + "Lorg/mozilla/javascript/Context;"
4486:                                        + ")Ljava/lang/Object;");
4487:                    }
4488:                }
4489:                generateExpression(child, node);
4490:                cfw.addALoad(contextLocal);
4491:                addScriptRuntimeInvoke("setObjectProp", "(Ljava/lang/Object;"
4492:                        + "Ljava/lang/String;" + "Ljava/lang/Object;"
4493:                        + "Lorg/mozilla/javascript/Context;"
4494:                        + ")Ljava/lang/Object;");
4495:            }
4496:
4497:            private void visitSetElem(int type, Node node, Node child) {
4498:                generateExpression(child, node);
4499:                child = child.getNext();
4500:                if (type == Token.SETELEM_OP) {
4501:                    cfw.add(ByteCode.DUP);
4502:                }
4503:                generateExpression(child, node);
4504:                child = child.getNext();
4505:                boolean indexIsNumber = (node
4506:                        .getIntProp(Node.ISNUMBER_PROP, -1) != -1);
4507:                if (type == Token.SETELEM_OP) {
4508:                    if (indexIsNumber) {
4509:                        // stack: ... object object number
4510:                        //        -> ... object number object number
4511:                        cfw.add(ByteCode.DUP2_X1);
4512:                        cfw.addALoad(contextLocal);
4513:                        addOptRuntimeInvoke("getObjectIndex",
4514:                                "(Ljava/lang/Object;D"
4515:                                        + "Lorg/mozilla/javascript/Context;"
4516:                                        + ")Ljava/lang/Object;");
4517:                    } else {
4518:                        // stack: ... object object indexObject
4519:                        //        -> ... object indexObject object indexObject
4520:                        cfw.add(ByteCode.DUP_X1);
4521:                        cfw.addALoad(contextLocal);
4522:                        addScriptRuntimeInvoke("getObjectElem",
4523:                                "(Ljava/lang/Object;" + "Ljava/lang/Object;"
4524:                                        + "Lorg/mozilla/javascript/Context;"
4525:                                        + ")Ljava/lang/Object;");
4526:                    }
4527:                }
4528:                generateExpression(child, node);
4529:                cfw.addALoad(contextLocal);
4530:                if (indexIsNumber) {
4531:                    addScriptRuntimeInvoke("setObjectIndex",
4532:                            "(Ljava/lang/Object;" + "D" + "Ljava/lang/Object;"
4533:                                    + "Lorg/mozilla/javascript/Context;"
4534:                                    + ")Ljava/lang/Object;");
4535:                } else {
4536:                    addScriptRuntimeInvoke("setObjectElem",
4537:                            "(Ljava/lang/Object;" + "Ljava/lang/Object;"
4538:                                    + "Ljava/lang/Object;"
4539:                                    + "Lorg/mozilla/javascript/Context;"
4540:                                    + ")Ljava/lang/Object;");
4541:                }
4542:            }
4543:
4544:            private void visitDotQuery(Node node, Node child) {
4545:                updateLineNumber(node);
4546:                generateExpression(child, node);
4547:                cfw.addALoad(variableObjectLocal);
4548:                addScriptRuntimeInvoke("enterDotQuery", "(Ljava/lang/Object;"
4549:                        + "Lorg/mozilla/javascript/Scriptable;"
4550:                        + ")Lorg/mozilla/javascript/Scriptable;");
4551:                cfw.addAStore(variableObjectLocal);
4552:
4553:                // add push null/pop with label in between to simplify code for loop
4554:                // continue when it is necessary to pop the null result from
4555:                // updateDotQuery
4556:                cfw.add(ByteCode.ACONST_NULL);
4557:                int queryLoopStart = cfw.acquireLabel();
4558:                cfw.markLabel(queryLoopStart); // loop continue jumps here
4559:                cfw.add(ByteCode.POP);
4560:
4561:                generateExpression(child.getNext(), node);
4562:                addScriptRuntimeInvoke("toBoolean", "(Ljava/lang/Object;)Z");
4563:                cfw.addALoad(variableObjectLocal);
4564:                addScriptRuntimeInvoke("updateDotQuery", "(Z"
4565:                        + "Lorg/mozilla/javascript/Scriptable;"
4566:                        + ")Ljava/lang/Object;");
4567:                cfw.add(ByteCode.DUP);
4568:                cfw.add(ByteCode.IFNULL, queryLoopStart);
4569:                // stack: ... non_null_result_of_updateDotQuery
4570:                cfw.addALoad(variableObjectLocal);
4571:                addScriptRuntimeInvoke("leaveDotQuery",
4572:                        "(Lorg/mozilla/javascript/Scriptable;"
4573:                                + ")Lorg/mozilla/javascript/Scriptable;");
4574:                cfw.addAStore(variableObjectLocal);
4575:            }
4576:
4577:            private int getLocalBlockRegister(Node node) {
4578:                Node localBlock = (Node) node.getProp(Node.LOCAL_BLOCK_PROP);
4579:                int localSlot = localBlock.getExistingIntProp(Node.LOCAL_PROP);
4580:                return localSlot;
4581:            }
4582:
4583:            private void dcpLoadAsNumber(int dcp_register) {
4584:                cfw.addALoad(dcp_register);
4585:                cfw.add(ByteCode.GETSTATIC, "java/lang/Void", "TYPE",
4586:                        "Ljava/lang/Class;");
4587:                int isNumberLabel = cfw.acquireLabel();
4588:                cfw.add(ByteCode.IF_ACMPEQ, isNumberLabel);
4589:                short stack = cfw.getStackTop();
4590:                cfw.addALoad(dcp_register);
4591:                addObjectToDouble();
4592:                int beyond = cfw.acquireLabel();
4593:                cfw.add(ByteCode.GOTO, beyond);
4594:                cfw.markLabel(isNumberLabel, stack);
4595:                cfw.addDLoad(dcp_register + 1);
4596:                cfw.markLabel(beyond);
4597:            }
4598:
4599:            private void dcpLoadAsObject(int dcp_register) {
4600:                cfw.addALoad(dcp_register);
4601:                cfw.add(ByteCode.GETSTATIC, "java/lang/Void", "TYPE",
4602:                        "Ljava/lang/Class;");
4603:                int isNumberLabel = cfw.acquireLabel();
4604:                cfw.add(ByteCode.IF_ACMPEQ, isNumberLabel);
4605:                short stack = cfw.getStackTop();
4606:                cfw.addALoad(dcp_register);
4607:                int beyond = cfw.acquireLabel();
4608:                cfw.add(ByteCode.GOTO, beyond);
4609:                cfw.markLabel(isNumberLabel, stack);
4610:                cfw.addDLoad(dcp_register + 1);
4611:                addDoubleWrap();
4612:                cfw.markLabel(beyond);
4613:            }
4614:
4615:            private void addGoto(Node target, int jumpcode) {
4616:                int targetLabel = getTargetLabel(target);
4617:                cfw.add(jumpcode, targetLabel);
4618:            }
4619:
4620:            private void addObjectToDouble() {
4621:                addScriptRuntimeInvoke("toNumber", "(Ljava/lang/Object;)D");
4622:            }
4623:
4624:            private void addNewObjectArray(int size) {
4625:                if (size == 0) {
4626:                    if (itsZeroArgArray >= 0) {
4627:                        cfw.addALoad(itsZeroArgArray);
4628:                    } else {
4629:                        cfw.add(ByteCode.GETSTATIC,
4630:                                "org/mozilla/javascript/ScriptRuntime",
4631:                                "emptyArgs", "[Ljava/lang/Object;");
4632:                    }
4633:                } else {
4634:                    cfw.addPush(size);
4635:                    cfw.add(ByteCode.ANEWARRAY, "java/lang/Object");
4636:                }
4637:            }
4638:
4639:            private void addScriptRuntimeInvoke(String methodName,
4640:                    String methodSignature) {
4641:                cfw.addInvoke(ByteCode.INVOKESTATIC,
4642:                        "org.mozilla.javascript.ScriptRuntime", methodName,
4643:                        methodSignature);
4644:            }
4645:
4646:            private void addOptRuntimeInvoke(String methodName,
4647:                    String methodSignature) {
4648:                cfw.addInvoke(ByteCode.INVOKESTATIC,
4649:                        "org/mozilla/javascript/optimizer/OptRuntime",
4650:                        methodName, methodSignature);
4651:            }
4652:
4653:            private void addJumpedBooleanWrap(int trueLabel, int falseLabel) {
4654:                cfw.markLabel(falseLabel);
4655:                int skip = cfw.acquireLabel();
4656:                cfw.add(ByteCode.GETSTATIC, "java/lang/Boolean", "FALSE",
4657:                        "Ljava/lang/Boolean;");
4658:                cfw.add(ByteCode.GOTO, skip);
4659:                cfw.markLabel(trueLabel);
4660:                cfw.add(ByteCode.GETSTATIC, "java/lang/Boolean", "TRUE",
4661:                        "Ljava/lang/Boolean;");
4662:                cfw.markLabel(skip);
4663:                cfw.adjustStackTop(-1); // only have 1 of true/false
4664:            }
4665:
4666:            private void addDoubleWrap() {
4667:                addOptRuntimeInvoke("wrapDouble", "(D)Ljava/lang/Double;");
4668:            }
4669:
4670:            /**
4671:             * Const locals use an extra slot to hold the has-been-assigned-once flag at
4672:             * runtime.
4673:             * @param isConst true iff the variable is const
4674:             * @return the register for the word pair (double/long)
4675:             */
4676:            private short getNewWordPairLocal(boolean isConst) {
4677:                short result = getConsecutiveSlots(2, isConst);
4678:                if (result < (MAX_LOCALS - 1)) {
4679:                    locals[result] = 1;
4680:                    locals[result + 1] = 1;
4681:                    if (isConst)
4682:                        locals[result + 2] = 1;
4683:                    if (result == firstFreeLocal) {
4684:                        for (int i = firstFreeLocal + 2; i < MAX_LOCALS; i++) {
4685:                            if (locals[i] == 0) {
4686:                                firstFreeLocal = (short) i;
4687:                                if (localsMax < firstFreeLocal)
4688:                                    localsMax = firstFreeLocal;
4689:                                return result;
4690:                            }
4691:                        }
4692:                    } else {
4693:                        return result;
4694:                    }
4695:                }
4696:                throw Context.reportRuntimeError("Program too complex "
4697:                        + "(out of locals)");
4698:            }
4699:
4700:            private short getNewWordLocal(boolean isConst) {
4701:                short result = getConsecutiveSlots(1, isConst);
4702:                if (result < (MAX_LOCALS - 1)) {
4703:                    locals[result] = 1;
4704:                    if (isConst)
4705:                        locals[result + 1] = 1;
4706:                    if (result == firstFreeLocal) {
4707:                        for (int i = firstFreeLocal + 2; i < MAX_LOCALS; i++) {
4708:                            if (locals[i] == 0) {
4709:                                firstFreeLocal = (short) i;
4710:                                if (localsMax < firstFreeLocal)
4711:                                    localsMax = firstFreeLocal;
4712:                                return result;
4713:                            }
4714:                        }
4715:                    } else {
4716:                        return result;
4717:                    }
4718:                }
4719:                throw Context.reportRuntimeError("Program too complex "
4720:                        + "(out of locals)");
4721:            }
4722:
4723:            private short getNewWordLocal() {
4724:                short result = firstFreeLocal;
4725:                locals[result] = 1;
4726:                for (int i = firstFreeLocal + 1; i < MAX_LOCALS; i++) {
4727:                    if (locals[i] == 0) {
4728:                        firstFreeLocal = (short) i;
4729:                        if (localsMax < firstFreeLocal)
4730:                            localsMax = firstFreeLocal;
4731:                        return result;
4732:                    }
4733:                }
4734:                throw Context.reportRuntimeError("Program too complex "
4735:                        + "(out of locals)");
4736:            }
4737:
4738:            private short getConsecutiveSlots(int count, boolean isConst) {
4739:                if (isConst)
4740:                    count++;
4741:                short result = firstFreeLocal;
4742:                while (true) {
4743:                    if (result >= (MAX_LOCALS - 1))
4744:                        break;
4745:                    int i;
4746:                    for (i = 0; i < count; i++)
4747:                        if (locals[result + i] != 0)
4748:                            break;
4749:                    if (i >= count)
4750:                        break;
4751:                    result++;
4752:                }
4753:                return result;
4754:            }
4755:
4756:            // This is a valid call only for a local that is allocated by default.
4757:            private void incReferenceWordLocal(short local) {
4758:                locals[local]++;
4759:            }
4760:
4761:            // This is a valid call only for a local that is allocated by default.
4762:            private void decReferenceWordLocal(short local) {
4763:                locals[local]--;
4764:            }
4765:
4766:            private void releaseWordLocal(short local) {
4767:                if (local < firstFreeLocal)
4768:                    firstFreeLocal = local;
4769:                locals[local] = 0;
4770:            }
4771:
4772:            static final int GENERATOR_TERMINATE = -1;
4773:            static final int GENERATOR_START = 0;
4774:            static final int GENERATOR_YIELD_START = 1;
4775:
4776:            ClassFileWriter cfw;
4777:            Codegen codegen;
4778:            CompilerEnvirons compilerEnv;
4779:            ScriptOrFnNode scriptOrFn;
4780:            public int scriptOrFnIndex;
4781:            private int savedCodeOffset;
4782:
4783:            private OptFunctionNode fnCurrent;
4784:            private boolean isTopLevel;
4785:
4786:            private static final int MAX_LOCALS = 256;
4787:            private int[] locals;
4788:            private short firstFreeLocal;
4789:            private short localsMax;
4790:
4791:            private int itsLineNumber;
4792:
4793:            private boolean hasVarsInRegs;
4794:            private short[] varRegisters;
4795:            private boolean inDirectCallFunction;
4796:            private boolean itsForcedObjectParameters;
4797:            private int enterAreaStartLabel;
4798:            private int epilogueLabel;
4799:
4800:            // special known locals. If you add a new local here, be sure
4801:            // to initialize it to -1 in initBodyGeneration
4802:            private short variableObjectLocal;
4803:            private short popvLocal;
4804:            private short contextLocal;
4805:            private short argsLocal;
4806:            private short operationLocal;
4807:            private short this ObjLocal;
4808:            private short funObjLocal;
4809:            private short itsZeroArgArray;
4810:            private short itsOneArgArray;
4811:            private short scriptRegexpLocal;
4812:            private short generatorStateLocal;
4813:
4814:            private boolean isGenerator;
4815:            private int generatorSwitch;
4816:            private int maxLocals = 0;
4817:            private int maxStack = 0;
4818:
4819:            private Hashtable finallys;
4820:
4821:            class FinallyReturnPoint {
4822:                public ArrayList jsrPoints = new ArrayList();
4823:                public int tableLabel = 0;
4824:            }
4825:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.