Source Code Cross Referenced for StandardASMCompiler.java in  » Scripting » jruby » org » jruby » compiler » impl » Java Source Code / Java DocumentationJava Source Code and Java Documentation

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


0001:        /***** BEGIN LICENSE BLOCK *****
0002:         * Version: CPL 1.0/GPL 2.0/LGPL 2.1
0003:         *
0004:         * The contents of this file are subject to the Common Public
0005:         * License Version 1.0 (the "License"); you may not use this file
0006:         * except in compliance with the License. You may obtain a copy of
0007:         * the License at http://www.eclipse.org/legal/cpl-v10.html
0008:         *
0009:         * Software distributed under the License is distributed on an "AS
0010:         * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
0011:         * implied. See the License for the specific language governing
0012:         * rights and limitations under the License.
0013:         *
0014:         * Copyright (C) 2006 Charles O Nutter <headius@headius.com>
0015:         *
0016:         * Alternatively, the contents of this file may be used under the terms of
0017:         * either of the GNU General Public License Version 2 or later (the "GPL"),
0018:         * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
0019:         * in which case the provisions of the GPL or the LGPL are applicable instead
0020:         * of those above. If you wish to allow use of your version of this file only
0021:         * under the terms of either the GPL or the LGPL, and not to allow others to
0022:         * use your version of this file under the terms of the CPL, indicate your
0023:         * decision by deleting the provisions above and replace them with the notice
0024:         * and other provisions required by the GPL or the LGPL. If you do not delete
0025:         * the provisions above, a recipient may use your version of this file under
0026:         * the terms of any one of the CPL, the GPL or the LGPL.
0027:         ***** END LICENSE BLOCK *****/package org.jruby.compiler.impl;
0028:
0029:        import java.io.File;
0030:        import java.io.FileOutputStream;
0031:        import java.io.IOException;
0032:        import java.io.PrintStream;
0033:        import java.math.BigInteger;
0034:        import java.util.HashMap;
0035:        import java.util.Map;
0036:        import java.util.Stack;
0037:
0038:        import jregex.Pattern;
0039:
0040:        import org.jruby.Ruby;
0041:        import org.jruby.RubyArray;
0042:        import org.jruby.RubyBignum;
0043:        import org.jruby.RubyBoolean;
0044:        import org.jruby.RubyClass;
0045:        import org.jruby.RubyFixnum;
0046:        import org.jruby.RubyFloat;
0047:        import org.jruby.RubyHash;
0048:        import org.jruby.RubyModule;
0049:        import org.jruby.RubyRange;
0050:        import org.jruby.RubyRegexp;
0051:        import org.jruby.RubyString;
0052:        import org.jruby.RubySymbol;
0053:        import org.jruby.ast.Node;
0054:        import org.jruby.ast.executable.Script;
0055:        import org.jruby.compiler.ArrayCallback;
0056:        import org.jruby.compiler.BranchCallback;
0057:        import org.jruby.compiler.ClosureCallback;
0058:        import org.jruby.compiler.Compiler;
0059:        import org.jruby.compiler.NotCompilableException;
0060:        import org.jruby.evaluator.EvaluationState;
0061:        import org.jruby.exceptions.JumpException;
0062:        import org.jruby.internal.runtime.GlobalVariables;
0063:        import org.jruby.javasupport.util.CompilerHelpers;
0064:        import org.jruby.lexer.yacc.ISourcePosition;
0065:        import org.jruby.parser.ReOptions;
0066:        import org.jruby.parser.StaticScope;
0067:        import org.jruby.runtime.Arity;
0068:        import org.jruby.runtime.Block;
0069:        import org.jruby.runtime.CallType;
0070:        import org.jruby.runtime.CallbackFactory;
0071:        import org.jruby.runtime.CompiledBlock;
0072:        import org.jruby.runtime.CompiledBlockCallback;
0073:        import org.jruby.runtime.DynamicScope;
0074:        import org.jruby.runtime.MethodIndex;
0075:        import org.jruby.runtime.ThreadContext;
0076:        import org.jruby.runtime.Visibility;
0077:        import org.jruby.runtime.builtin.IRubyObject;
0078:        import org.jruby.util.ByteList;
0079:        import org.jruby.util.CodegenUtils;
0080:        import org.jruby.util.JRubyClassLoader;
0081:        import org.objectweb.asm.ClassVisitor;
0082:        import org.objectweb.asm.ClassWriter;
0083:        import org.objectweb.asm.Label;
0084:        import org.objectweb.asm.Opcodes;
0085:
0086:        /**
0087:         *
0088:         * @author headius
0089:         */
0090:        public class StandardASMCompiler implements  Compiler, Opcodes {
0091:            private static final CodegenUtils cg = CodegenUtils.cg;
0092:            private static final String THREADCONTEXT = cg
0093:                    .p(ThreadContext.class);
0094:            private static final String RUBY = cg.p(Ruby.class);
0095:            private static final String IRUBYOBJECT = cg.p(IRubyObject.class);
0096:
0097:            private static final String METHOD_SIGNATURE = cg.sig(
0098:                    IRubyObject.class,
0099:                    new Class[] { ThreadContext.class, IRubyObject.class,
0100:                            IRubyObject[].class, Block.class });
0101:            private static final String CLOSURE_SIGNATURE = cg.sig(
0102:                    IRubyObject.class, new Class[] { ThreadContext.class,
0103:                            IRubyObject.class, IRubyObject[].class });
0104:
0105:            private static final int THREADCONTEXT_INDEX = 0;
0106:            private static final int SELF_INDEX = 1;
0107:            private static final int ARGS_INDEX = 2;
0108:            private static final int CLOSURE_INDEX = 3;
0109:            private static final int SCOPE_INDEX = 4;
0110:            private static final int RUNTIME_INDEX = 5;
0111:            private static final int VISIBILITY_INDEX = 6;
0112:            private static final int LOCAL_VARS_INDEX = 7;
0113:
0114:            private Stack SkinnyMethodAdapters = new Stack();
0115:            private Stack arities = new Stack();
0116:            private Stack scopeStarts = new Stack();
0117:
0118:            private String classname;
0119:            private String sourcename;
0120:
0121:            //Map classWriters = new HashMacg.p();
0122:            private ClassWriter classWriter;
0123:            ClassWriter currentMultiStub = null;
0124:            int methodIndex = -1;
0125:            int multiStubCount = -1;
0126:            int innerIndex = -1;
0127:
0128:            int lastLine = -1;
0129:
0130:            /**
0131:             * Used to make determinations about non-local returns and similar flow control
0132:             */
0133:            boolean isCompilingClosure;
0134:
0135:            /** Creates a new instance of StandardCompilerContext */
0136:            public StandardASMCompiler(String classname, String sourcename) {
0137:                this .classname = classname;
0138:                this .sourcename = sourcename;
0139:            }
0140:
0141:            public StandardASMCompiler(Node node) {
0142:                // determine new class name based on filename of incoming node
0143:                // must generate unique classnames for evals, since they could be generated many times in a given run
0144:                classname = "EVAL" + hashCode();
0145:                sourcename = "EVAL" + hashCode();
0146:            }
0147:
0148:            public Class loadClass(JRubyClassLoader classLoader)
0149:                    throws ClassNotFoundException {
0150:                classLoader.defineClass(cg.c(classname), classWriter
0151:                        .toByteArray());
0152:
0153:                return classLoader.loadClass(cg.c(classname));
0154:            }
0155:
0156:            public void writeClass(File destination) throws IOException {
0157:                writeClass(classname, destination, classWriter);
0158:            }
0159:
0160:            private void writeClass(String classname, File destination,
0161:                    ClassWriter writer) throws IOException {
0162:                String fullname = classname + ".class";
0163:                String filename = null;
0164:                String path = null;
0165:                if (fullname.lastIndexOf("/") == -1) {
0166:                    filename = fullname;
0167:                    path = "";
0168:                } else {
0169:                    filename = fullname
0170:                            .substring(fullname.lastIndexOf("/") + 1);
0171:                    path = fullname.substring(0, fullname.lastIndexOf("/"));
0172:                }
0173:                // create dir if necessary
0174:                File pathfile = new File(destination, path);
0175:                pathfile.mkdirs();
0176:
0177:                FileOutputStream out = new FileOutputStream(new File(pathfile,
0178:                        filename));
0179:
0180:                out.write(writer.toByteArray());
0181:            }
0182:
0183:            public String getClassname() {
0184:                return classname;
0185:            }
0186:
0187:            public String getSourcename() {
0188:                return sourcename;
0189:            }
0190:
0191:            public ClassVisitor getClassVisitor() {
0192:                return classWriter;
0193:            }
0194:
0195:            public SkinnyMethodAdapter getMethodAdapter() {
0196:                return (SkinnyMethodAdapter) SkinnyMethodAdapters.peek();
0197:            }
0198:
0199:            public SkinnyMethodAdapter popMethodAdapter() {
0200:                return (SkinnyMethodAdapter) SkinnyMethodAdapters.pop();
0201:            }
0202:
0203:            public void pushMethodAdapter(SkinnyMethodAdapter mv) {
0204:                SkinnyMethodAdapters.push(mv);
0205:            }
0206:
0207:            public int getArity() {
0208:                return ((Integer) arities.peek()).intValue();
0209:            }
0210:
0211:            public void pushArity(Arity arity) {
0212:                arities.push(arity);
0213:            }
0214:
0215:            public Arity popArity() {
0216:                return (Arity) arities.pop();
0217:            }
0218:
0219:            public void pushScopeStart(Label start) {
0220:                scopeStarts.push(start);
0221:            }
0222:
0223:            public Label popScopeStart() {
0224:                return (Label) scopeStarts.pop();
0225:            }
0226:
0227:            public void startScript() {
0228:                classWriter = new ClassWriter(true);
0229:
0230:                // Create the class with the appropriate class name and source file
0231:                classWriter.visit(V1_4, ACC_PUBLIC + ACC_SUPER, classname,
0232:                        null, cg.p(Object.class), new String[] { cg
0233:                                .p(Script.class) });
0234:                classWriter.visitSource(sourcename, null);
0235:
0236:                createClassInit();
0237:                createConstructor();
0238:            }
0239:
0240:            public void endScript() {
0241:                // add Script#run impl, used for running this script with a specified threadcontext and self
0242:                // root method of a script is always in __load__ method
0243:                String methodName = "__file__";
0244:                SkinnyMethodAdapter mv = new SkinnyMethodAdapter(
0245:                        getClassVisitor().visitMethod(ACC_PUBLIC, "run",
0246:                                METHOD_SIGNATURE, null, null));
0247:                mv.start();
0248:
0249:                // invoke __file__ with threadcontext, self, args (null), and block (null)
0250:                // These are all +1 because run is an instance method where others are static
0251:                mv.aload(THREADCONTEXT_INDEX + 1);
0252:                mv.aload(SELF_INDEX + 1);
0253:                mv.aload(ARGS_INDEX + 1);
0254:                mv.aload(CLOSURE_INDEX + 1);
0255:
0256:                mv.invokestatic(classname, methodName, METHOD_SIGNATURE);
0257:                mv.areturn();
0258:                mv.end();
0259:
0260:                // add main impl, used for detached or command-line execution of this script with a new runtime
0261:                // root method of a script is always in stub0, method0
0262:                mv = new SkinnyMethodAdapter(getClassVisitor().visitMethod(
0263:                        ACC_PUBLIC | ACC_STATIC, "main",
0264:                        cg.sig(Void.TYPE, cg.params(String[].class)), null,
0265:                        null));
0266:                mv.start();
0267:
0268:                // new instance to invoke run against
0269:                mv.newobj(classname);
0270:                mv.dup();
0271:                mv.invokespecial(classname, "<init>", cg.sig(Void.TYPE));
0272:
0273:                // invoke run with threadcontext and topself
0274:                mv.invokestatic(cg.p(Ruby.class), "getDefaultInstance", cg
0275:                        .sig(Ruby.class));
0276:                mv.dup();
0277:
0278:                mv.invokevirtual(RUBY, "getCurrentContext", cg
0279:                        .sig(ThreadContext.class));
0280:                mv.swap();
0281:                mv.invokevirtual(RUBY, "getTopSelf", cg.sig(IRubyObject.class));
0282:                mv.getstatic(cg.p(IRubyObject.class), "NULL_ARRAY", cg
0283:                        .ci(IRubyObject[].class));
0284:                mv.getstatic(cg.p(Block.class), "NULL_BLOCK", cg
0285:                        .ci(Block.class));
0286:
0287:                mv.invokevirtual(classname, "run", METHOD_SIGNATURE);
0288:                mv.voidreturn();
0289:                mv.end();
0290:            }
0291:
0292:            private void createConstructor() {
0293:                ClassVisitor cv = getClassVisitor();
0294:
0295:                SkinnyMethodAdapter mv = new SkinnyMethodAdapter(cv
0296:                        .visitMethod(ACC_PUBLIC, "<init>", cg.sig(Void.TYPE),
0297:                                null, null));
0298:                mv.start();
0299:                mv.aload(0);
0300:                mv.invokespecial(cg.p(Object.class), "<init>", cg
0301:                        .sig(Void.TYPE));
0302:                mv.voidreturn();
0303:                mv.end();
0304:            }
0305:
0306:            private void createClassInit() {
0307:                ClassVisitor cv = getClassVisitor();
0308:
0309:                cv.visitField(ACC_STATIC | ACC_PRIVATE | ACC_FINAL,
0310:                        "$isClassLoaded", cg.ci(Boolean.TYPE), null,
0311:                        Boolean.FALSE);
0312:                cv.visitField(ACC_STATIC | ACC_PRIVATE | ACC_FINAL, "$class",
0313:                        cg.ci(Class.class), null, null);
0314:
0315:                SkinnyMethodAdapter mv = new SkinnyMethodAdapter(cv
0316:                        .visitMethod(ACC_PUBLIC, "<clinit>", cg.sig(Void.TYPE),
0317:                                null, null));
0318:                mv.start();
0319:
0320:                // This is a little hacky...since clinit recurses, set a boolean so we don't continue trying to load class
0321:                mv.getstatic(classname, "$isClassLoaded", cg.ci(Boolean.TYPE));
0322:                Label doNotLoadClass = new Label();
0323:                mv.ifne(doNotLoadClass);
0324:
0325:                mv.ldc(Boolean.TRUE);
0326:                mv.putstatic(classname, "$isClassLoaded", cg.ci(Boolean.TYPE));
0327:                mv.ldc(cg.c(classname));
0328:                mv.invokestatic(cg.p(Class.class), "forName", cg.sig(
0329:                        Class.class, cg.params(String.class)));
0330:                mv.putstatic(classname, "$class", cg.ci(Class.class));
0331:
0332:                mv.label(doNotLoadClass);
0333:                mv.voidreturn();
0334:                mv.end();
0335:            }
0336:
0337:            public Object beginMethod(String friendlyName, ClosureCallback args) {
0338:                SkinnyMethodAdapter newMethod = new SkinnyMethodAdapter(
0339:                        getClassVisitor().visitMethod(ACC_PUBLIC | ACC_STATIC,
0340:                                friendlyName, METHOD_SIGNATURE, null, null));
0341:                pushMethodAdapter(newMethod);
0342:
0343:                newMethod.start();
0344:
0345:                // set up a local IRuby variable
0346:                newMethod.aload(THREADCONTEXT_INDEX);
0347:                invokeThreadContext("getRuntime", cg.sig(Ruby.class));
0348:                newMethod.astore(RUNTIME_INDEX);
0349:
0350:                // set visibility
0351:                newMethod.getstatic(cg.p(Visibility.class), "PRIVATE", cg
0352:                        .ci(Visibility.class));
0353:                newMethod.astore(VISIBILITY_INDEX);
0354:
0355:                // store the local vars in a local variable
0356:                loadThreadContext();
0357:                invokeThreadContext("getCurrentScope", cg
0358:                        .sig(DynamicScope.class));
0359:                newMethod.dup();
0360:                newMethod.astore(LOCAL_VARS_INDEX);
0361:                newMethod.invokevirtual(cg.p(DynamicScope.class), "getValues",
0362:                        cg.sig(IRubyObject[].class));
0363:                newMethod.astore(SCOPE_INDEX);
0364:
0365:                if (args != null) {
0366:                    args.compile(this );
0367:                } else {
0368:                    pushArity(null);
0369:                }
0370:
0371:                // visit a label to start scoping for local vars in this method
0372:                Label start = new Label();
0373:                newMethod.label(start);
0374:                pushScopeStart(start);
0375:
0376:                return newMethod;
0377:            }
0378:
0379:            public void endMethod(Object token) {
0380:                assert token instanceof  SkinnyMethodAdapter;
0381:
0382:                SkinnyMethodAdapter mv = (SkinnyMethodAdapter) token;
0383:                // return last value from execution
0384:                mv.areturn();
0385:
0386:                // end of variable scope
0387:                Label end = new Label();
0388:                mv.label(end);
0389:
0390:                // local variable for lvars array
0391:                mv.visitLocalVariable("lvars", cg.ci(IRubyObject[].class),
0392:                        null, popScopeStart(), end, LOCAL_VARS_INDEX);
0393:
0394:                mv.end();
0395:
0396:                popMethodAdapter();
0397:                popArity();
0398:            }
0399:
0400:            public void lineNumber(ISourcePosition position) {
0401:                if (lastLine == (lastLine = position.getEndLine()))
0402:                    return; // did not change lines for this node, don't bother relabeling
0403:
0404:                Label l = new Label();
0405:                SkinnyMethodAdapter mv = getMethodAdapter();
0406:                mv.label(l);
0407:                // line numbers are zero-based; add one for them to make sense in an editor
0408:                mv.visitLineNumber(position.getStartLine() + 1, l);
0409:            }
0410:
0411:            public void invokeAttrAssign(String name) {
0412:                SkinnyMethodAdapter mv = getMethodAdapter();
0413:
0414:                // start with [recv, args]
0415:
0416:                // get args[length - 1] and stuff it under the receiver
0417:                // dup args * 2
0418:                mv.dup(); // [recv, args, args]
0419:                mv.dup(); // [recv, args, args, args]
0420:                mv.arraylength(); // [recv, args, args, len]
0421:                mv.iconst_1(); // [recv, args, args, len, 1]
0422:                mv.isub(); // [recv, args, args, len-1]
0423:                // load from array
0424:                mv.arrayload(); // [recv, args, val]
0425:                mv.dup_x2(); // [val, recv, args, val]
0426:                mv.pop(); // [val, recv, args]
0427:
0428:                invokeDynamic(name, true, true, CallType.NORMAL, null, true); // [val, result]
0429:
0430:                // pop result, use args[length - 1] captured above
0431:                mv.pop(); // [val]
0432:            }
0433:
0434:            public void invokeDynamic(String name, boolean hasReceiver,
0435:                    boolean hasArgs, CallType callType,
0436:                    ClosureCallback closureArg, boolean attrAssign) {
0437:                SkinnyMethodAdapter mv = getMethodAdapter();
0438:                String callSig = cg.sig(IRubyObject.class, cg.params(
0439:                        IRubyObject.class, IRubyObject[].class,
0440:                        ThreadContext.class, String.class, IRubyObject.class,
0441:                        CallType.class, Block.class));
0442:                String callSigIndexed = cg.sig(IRubyObject.class, cg.params(
0443:                        IRubyObject.class, IRubyObject[].class,
0444:                        ThreadContext.class, Byte.TYPE, String.class,
0445:                        IRubyObject.class, CallType.class, Block.class));
0446:
0447:                int index = MethodIndex.getIndex(name);
0448:
0449:                if (hasArgs) {
0450:                    if (hasReceiver) {
0451:                        // Call with args
0452:                        // receiver already present
0453:                    } else {
0454:                        // FCall
0455:                        // no receiver present, use self
0456:                        loadSelf();
0457:                        // put self under args
0458:                        mv.swap();
0459:                    }
0460:                } else {
0461:                    if (hasReceiver) {
0462:                        // receiver already present
0463:                        // empty args list
0464:                        mv.getstatic(cg.p(IRubyObject.class), "NULL_ARRAY", cg
0465:                                .ci(IRubyObject[].class));
0466:
0467:                    } else {
0468:                        // VCall
0469:                        // no receiver present, use self
0470:                        loadSelf();
0471:
0472:                        // empty args list
0473:                        mv.getstatic(cg.p(IRubyObject.class), "NULL_ARRAY", cg
0474:                                .ci(IRubyObject[].class));
0475:                    }
0476:                }
0477:
0478:                loadThreadContext();
0479:
0480:                if (index != 0) {
0481:                    // load method index
0482:                    mv.ldc(new Integer(index));
0483:                }
0484:
0485:                mv.ldc(name);
0486:
0487:                // load self for visibility checks
0488:                loadSelf();
0489:
0490:                mv.getstatic(cg.p(CallType.class), callType.toString(), cg
0491:                        .ci(CallType.class));
0492:
0493:                if (closureArg == null) {
0494:                    mv.getstatic(cg.p(Block.class), "NULL_BLOCK", cg
0495:                            .ci(Block.class));
0496:                } else {
0497:                    closureArg.compile(this );
0498:                }
0499:
0500:                Label tryBegin = new Label();
0501:                Label tryEnd = new Label();
0502:                Label tryCatch = new Label();
0503:                if (closureArg != null) {
0504:                    // wrap with try/catch for block flow-control exceptions
0505:                    // FIXME: for flow-control from containing blocks, but it's not working right;
0506:                    // stack is not as expected for invoke calls below...
0507:                    //mv.trycatch(tryBegin, tryEnd, tryCatch, cg.p(JumpException.class));
0508:
0509:                    mv.label(tryBegin);
0510:                }
0511:
0512:                if (attrAssign) {
0513:                    if (index != 0) {
0514:                        invokeUtilityMethod("doAttrAssignIndexed",
0515:                                callSigIndexed);
0516:                    } else {
0517:                        invokeUtilityMethod("doAttrAssign", callSig);
0518:                    }
0519:                } else {
0520:                    if (index != 0) {
0521:                        invokeUtilityMethod("doInvokeDynamicIndexed",
0522:                                callSigIndexed);
0523:                    } else {
0524:                        invokeUtilityMethod("doInvokeDynamic", callSig);
0525:                    }
0526:                }
0527:
0528:                if (closureArg != null) {
0529:                    mv.label(tryEnd);
0530:
0531:                    // no physical break, terminate loop and skip catch block
0532:                    Label normalEnd = new Label();
0533:                    mv.go_to(normalEnd);
0534:
0535:                    mv.label(tryCatch);
0536:                    {
0537:                        loadClosure();
0538:                        invokeUtilityMethod("handleJumpException", cg.sig(
0539:                                IRubyObject.class, cg.params(
0540:                                        JumpException.class, Block.class)));
0541:                    }
0542:
0543:                    mv.label(normalEnd);
0544:                }
0545:            }
0546:
0547:            public void yield(boolean hasArgs) {
0548:                loadClosure();
0549:
0550:                SkinnyMethodAdapter method = getMethodAdapter();
0551:
0552:                if (hasArgs) {
0553:                    method.swap();
0554:
0555:                    loadThreadContext();
0556:                    method.swap();
0557:
0558:                    // args now here
0559:                } else {
0560:                    loadThreadContext();
0561:
0562:                    // empty args
0563:                    method.aconst_null();
0564:                }
0565:
0566:                method.aconst_null();
0567:                method.aconst_null();
0568:                method.ldc(Boolean.FALSE);
0569:
0570:                method.invokevirtual(cg.p(Block.class), "yield", cg.sig(
0571:                        IRubyObject.class, cg.params(ThreadContext.class,
0572:                                IRubyObject.class, IRubyObject.class,
0573:                                RubyModule.class, Boolean.TYPE)));
0574:            }
0575:
0576:            private void invokeIRubyObject(String methodName, String signature) {
0577:                getMethodAdapter().invokeinterface(IRUBYOBJECT, methodName,
0578:                        signature);
0579:            }
0580:
0581:            public void loadThreadContext() {
0582:                getMethodAdapter().aload(THREADCONTEXT_INDEX);
0583:            }
0584:
0585:            public void loadClosure() {
0586:                loadThreadContext();
0587:                invokeThreadContext("getFrameBlock", cg.sig(Block.class));
0588:            }
0589:
0590:            public void loadSelf() {
0591:                getMethodAdapter().aload(SELF_INDEX);
0592:            }
0593:
0594:            public void loadRuntime() {
0595:                getMethodAdapter().aload(RUNTIME_INDEX);
0596:            }
0597:
0598:            public void loadVisibility() {
0599:                getMethodAdapter().aload(VISIBILITY_INDEX);
0600:            }
0601:
0602:            public void loadNil() {
0603:                loadRuntime();
0604:                invokeIRuby("getNil", cg.sig(IRubyObject.class));
0605:            }
0606:
0607:            public void loadSymbol(String symbol) {
0608:                loadRuntime();
0609:
0610:                SkinnyMethodAdapter mv = getMethodAdapter();
0611:
0612:                mv.ldc(symbol);
0613:
0614:                invokeIRuby("newSymbol", cg.sig(RubySymbol.class, cg
0615:                        .params(String.class)));
0616:            }
0617:
0618:            public void loadObject() {
0619:                loadRuntime();
0620:
0621:                invokeIRuby("getObject", cg.sig(RubyClass.class, cg.params()));
0622:            }
0623:
0624:            public void consumeCurrentValue() {
0625:                getMethodAdapter().pop();
0626:            }
0627:
0628:            public void duplicateCurrentValue() {
0629:                getMethodAdapter().dup();
0630:            }
0631:
0632:            public void swapValues() {
0633:                getMethodAdapter().swap();
0634:            }
0635:
0636:            public void retrieveSelf() {
0637:                loadSelf();
0638:            }
0639:
0640:            public void retrieveSelfClass() {
0641:                loadSelf();
0642:                invokeIRubyObject("getMetaClass", cg.sig(RubyClass.class));
0643:            }
0644:
0645:            public void assignLocalVariable(int index) {
0646:                SkinnyMethodAdapter mv = getMethodAdapter();
0647:                mv.dup();
0648:
0649:                mv.aload(SCOPE_INDEX);
0650:                mv.swap();
0651:                mv.ldc(new Integer(index));
0652:                mv.swap();
0653:                mv.arraystore();
0654:            }
0655:
0656:            public void assignLastLine() {
0657:                SkinnyMethodAdapter mv = getMethodAdapter();
0658:                mv.dup();
0659:
0660:                loadThreadContext();
0661:                invokeThreadContext("getCurrentScope", cg
0662:                        .sig(DynamicScope.class));
0663:                mv.swap();
0664:                mv.invokevirtual(cg.p(DynamicScope.class), "setLastLine", cg
0665:                        .sig(Void.TYPE, cg.params(IRubyObject.class)));
0666:            }
0667:
0668:            public void assignLocalVariableBlockArg(int argIndex, int varIndex) {
0669:                SkinnyMethodAdapter mv = getMethodAdapter();
0670:
0671:                // this is copying values, but it would be more efficient to just use the args in-place
0672:                mv.aload(LOCAL_VARS_INDEX);
0673:                mv.ldc(new Integer(varIndex));
0674:                mv.aload(ARGS_INDEX);
0675:                mv.ldc(new Integer(argIndex));
0676:                mv.arrayload();
0677:                mv.iconst_0();
0678:                mv.invokevirtual(cg.p(DynamicScope.class), "setValue", cg.sig(
0679:                        Void.TYPE, cg.params(Integer.TYPE, IRubyObject.class,
0680:                                Integer.TYPE)));
0681:            }
0682:
0683:            public void retrieveLocalVariable(int index) {
0684:                SkinnyMethodAdapter mv = getMethodAdapter();
0685:
0686:                mv.aload(SCOPE_INDEX);
0687:                mv.ldc(new Integer(index));
0688:                mv.arrayload();
0689:                nullToNil();
0690:            }
0691:
0692:            public void retrieveLastLine() {
0693:                SkinnyMethodAdapter mv = getMethodAdapter();
0694:
0695:                loadThreadContext();
0696:                invokeThreadContext("getCurrentScope", cg
0697:                        .sig(DynamicScope.class));
0698:                mv.invokevirtual(cg.p(DynamicScope.class), "getLastLine", cg
0699:                        .sig(IRubyObject.class));
0700:                nullToNil();
0701:            }
0702:
0703:            public void retrieveBackRef() {
0704:                SkinnyMethodAdapter mv = getMethodAdapter();
0705:
0706:                loadThreadContext();
0707:                invokeThreadContext("getCurrentScope", cg
0708:                        .sig(DynamicScope.class));
0709:                mv.invokevirtual(cg.p(DynamicScope.class), "getBackRef", cg
0710:                        .sig(IRubyObject.class));
0711:                nullToNil();
0712:            }
0713:
0714:            public void assignLocalVariable(int index, int depth) {
0715:                if (depth == 0) {
0716:                    assignLocalVariable(index);
0717:                    return;
0718:                }
0719:
0720:                SkinnyMethodAdapter mv = getMethodAdapter();
0721:                mv.dup();
0722:
0723:                mv.aload(LOCAL_VARS_INDEX);
0724:                mv.swap();
0725:                mv.ldc(new Integer(index));
0726:                mv.swap();
0727:                mv.ldc(new Integer(depth));
0728:                mv.invokevirtual(cg.p(DynamicScope.class), "setValue", cg.sig(
0729:                        Void.TYPE, cg.params(Integer.TYPE, IRubyObject.class,
0730:                                Integer.TYPE)));
0731:            }
0732:
0733:            public void assignLocalVariableBlockArg(int argIndex, int varIndex,
0734:                    int depth) {
0735:                if (depth == 0) {
0736:                    assignLocalVariableBlockArg(argIndex, varIndex);
0737:                    return;
0738:                }
0739:
0740:                SkinnyMethodAdapter mv = getMethodAdapter();
0741:
0742:                mv.aload(LOCAL_VARS_INDEX);
0743:                mv.ldc(new Integer(varIndex));
0744:                mv.aload(ARGS_INDEX);
0745:                mv.ldc(new Integer(argIndex));
0746:                mv.arrayload();
0747:                mv.ldc(new Integer(depth));
0748:                mv.invokevirtual(cg.p(DynamicScope.class), "setValue", cg.sig(
0749:                        Void.TYPE, cg.params(Integer.TYPE, IRubyObject.class,
0750:                                Integer.TYPE)));
0751:            }
0752:
0753:            public void retrieveLocalVariable(int index, int depth) {
0754:                if (depth == 0) {
0755:                    retrieveLocalVariable(index);
0756:                    return;
0757:                }
0758:
0759:                SkinnyMethodAdapter mv = getMethodAdapter();
0760:
0761:                mv.aload(LOCAL_VARS_INDEX);
0762:                mv.ldc(new Integer(index));
0763:                mv.ldc(new Integer(depth));
0764:                mv.invokevirtual(cg.p(DynamicScope.class), "getValue", cg.sig(
0765:                        IRubyObject.class, cg
0766:                                .params(Integer.TYPE, Integer.TYPE)));
0767:                nullToNil();
0768:            }
0769:
0770:            public void assignConstantInCurrent(String name) {
0771:                SkinnyMethodAdapter mv = getMethodAdapter();
0772:
0773:                loadThreadContext();
0774:                mv.ldc(name);
0775:                mv.dup2_x1();
0776:                mv.pop2();
0777:                invokeThreadContext("setConstantInCurrent", cg.sig(
0778:                        IRubyObject.class, cg.params(String.class,
0779:                                IRubyObject.class)));
0780:            }
0781:
0782:            public void assignConstantInModule(String name) {
0783:                SkinnyMethodAdapter mv = getMethodAdapter();
0784:
0785:                loadThreadContext();
0786:                mv.ldc(name);
0787:                mv.swap2();
0788:                invokeThreadContext("setConstantInCurrent", cg.sig(
0789:                        IRubyObject.class, cg.params(String.class,
0790:                                RubyModule.class, IRubyObject.class)));
0791:            }
0792:
0793:            public void assignConstantInObject(String name) {
0794:                SkinnyMethodAdapter mv = getMethodAdapter();
0795:
0796:                // load Object under value
0797:                loadRuntime();
0798:                invokeIRuby("getObject", cg.sig(RubyClass.class, cg.params()));
0799:                mv.swap();
0800:
0801:                assignConstantInModule(name);
0802:            }
0803:
0804:            public void retrieveConstant(String name) {
0805:                SkinnyMethodAdapter mv = getMethodAdapter();
0806:
0807:                loadThreadContext();
0808:                mv.ldc(name);
0809:                invokeThreadContext("getConstant", cg.sig(IRubyObject.class, cg
0810:                        .params(String.class)));
0811:            }
0812:
0813:            public void retrieveConstantFromModule(String name) {
0814:                SkinnyMethodAdapter mv = getMethodAdapter();
0815:                mv.visitTypeInsn(CHECKCAST, cg.p(RubyModule.class));
0816:                mv.ldc(name);
0817:                mv.invokevirtual(cg.p(RubyModule.class), "getConstantFrom", cg
0818:                        .sig(IRubyObject.class, cg.params(String.class)));
0819:            }
0820:
0821:            public void retrieveClassVariable(String name) {
0822:                loadThreadContext();
0823:                loadRuntime();
0824:                loadSelf();
0825:                getMethodAdapter().ldc(name);
0826:
0827:                invokeUtilityMethod("fetchClassVariable", cg.sig(
0828:                        IRubyObject.class, cg.params(ThreadContext.class,
0829:                                Ruby.class, IRubyObject.class, String.class)));
0830:            }
0831:
0832:            public void assignClassVariable(String name) {
0833:                SkinnyMethodAdapter method = getMethodAdapter();
0834:
0835:                loadThreadContext();
0836:                method.swap();
0837:                loadRuntime();
0838:                method.swap();
0839:                loadSelf();
0840:                method.swap();
0841:                getMethodAdapter().ldc(name);
0842:                method.swap();
0843:
0844:                invokeUtilityMethod("setClassVariable", cg.sig(
0845:                        IRubyObject.class, cg.params(ThreadContext.class,
0846:                                Ruby.class, IRubyObject.class, String.class,
0847:                                IRubyObject.class)));
0848:            }
0849:
0850:            private void loadScope(int depth) {
0851:                SkinnyMethodAdapter mv = getMethodAdapter();
0852:                // get the appropriate array out of the scopes
0853:                mv.aload(SCOPE_INDEX);
0854:                mv.ldc(new Integer(depth - 1));
0855:                mv.arrayload();
0856:            }
0857:
0858:            public void createNewFloat(double value) {
0859:                SkinnyMethodAdapter mv = getMethodAdapter();
0860:
0861:                loadRuntime();
0862:                mv.ldc(new Double(value));
0863:
0864:                invokeIRuby("newFloat", cg.sig(RubyFloat.class, cg
0865:                        .params(Double.TYPE)));
0866:            }
0867:
0868:            public void createNewFixnum(long value) {
0869:                SkinnyMethodAdapter mv = getMethodAdapter();
0870:
0871:                loadRuntime();
0872:                mv.ldc(new Long(value));
0873:
0874:                invokeIRuby("newFixnum", cg.sig(RubyFixnum.class, cg
0875:                        .params(Long.TYPE)));
0876:            }
0877:
0878:            public void createNewBignum(BigInteger value) {
0879:                SkinnyMethodAdapter mv = getMethodAdapter();
0880:
0881:                loadRuntime();
0882:                mv.ldc(value.toString());
0883:
0884:                mv.invokestatic(cg.p(RubyBignum.class), "newBignum", cg.sig(
0885:                        RubyBignum.class, cg.params(Ruby.class, String.class)));
0886:            }
0887:
0888:            public void createNewString(ArrayCallback callback, int count) {
0889:                SkinnyMethodAdapter mv = getMethodAdapter();
0890:                loadRuntime();
0891:                invokeIRuby("newString", cg.sig(RubyString.class, cg.params()));
0892:                for (int i = 0; i < count; i++) {
0893:                    callback.nextValue(this , null, i);
0894:                    mv.invokevirtual(cg.p(RubyString.class), "append", cg.sig(
0895:                            RubyString.class, cg.params(IRubyObject.class)));
0896:                }
0897:            }
0898:
0899:            public void createNewString(ByteList value) {
0900:                SkinnyMethodAdapter mv = getMethodAdapter();
0901:
0902:                // FIXME: this is sub-optimal, storing string value in a java.lang.String again
0903:                loadRuntime();
0904:                mv.ldc(value.toString());
0905:
0906:                invokeIRuby("newString", cg.sig(RubyString.class, cg
0907:                        .params(String.class)));
0908:            }
0909:
0910:            public void createNewSymbol(String name) {
0911:                loadRuntime();
0912:                getMethodAdapter().ldc(name);
0913:                invokeIRuby("newSymbol", cg.sig(RubySymbol.class, cg
0914:                        .params(String.class)));
0915:            }
0916:
0917:            public void createNewArray() {
0918:                SkinnyMethodAdapter mv = getMethodAdapter();
0919:
0920:                loadRuntime();
0921:                // put under object array already present
0922:                mv.swap();
0923:
0924:                invokeIRuby("newArrayNoCopy", cg.sig(RubyArray.class, cg
0925:                        .params(IRubyObject[].class)));
0926:            }
0927:
0928:            public void createEmptyArray() {
0929:                SkinnyMethodAdapter mv = getMethodAdapter();
0930:
0931:                loadRuntime();
0932:
0933:                invokeIRuby("newArray", cg.sig(RubyArray.class, cg.params()));
0934:            }
0935:
0936:            public void createObjectArray(Object[] sourceArray,
0937:                    ArrayCallback callback) {
0938:                buildObjectArray(IRUBYOBJECT, sourceArray, callback);
0939:            }
0940:
0941:            public void createObjectArray(int elementCount) {
0942:                SkinnyMethodAdapter method = getMethodAdapter();
0943:
0944:                // create the array
0945:                method.ldc(new Integer(elementCount));
0946:                method.anewarray(cg.p(IRubyObject.class));
0947:
0948:                // for each element, swap with array and insert
0949:                for (int i = 0; i < elementCount; i++) {
0950:                    method.dup_x1();
0951:                    method.dup_x1();
0952:                    method.pop();
0953:
0954:                    method.ldc(new Integer(elementCount - 1 - i));
0955:                    method.swap();
0956:
0957:                    method.arraystore();
0958:                }
0959:            }
0960:
0961:            private void buildObjectArray(String type, Object[] sourceArray,
0962:                    ArrayCallback callback) {
0963:                SkinnyMethodAdapter mv = getMethodAdapter();
0964:
0965:                mv.ldc(new Integer(sourceArray.length));
0966:                mv.anewarray(type);
0967:
0968:                for (int i = 0; i < sourceArray.length; i++) {
0969:                    mv.dup();
0970:                    mv.ldc(new Integer(i));
0971:
0972:                    callback.nextValue(this , sourceArray, i);
0973:
0974:                    mv.arraystore();
0975:                }
0976:            }
0977:
0978:            public void createEmptyHash() {
0979:                SkinnyMethodAdapter mv = getMethodAdapter();
0980:
0981:                loadRuntime();
0982:
0983:                mv.invokestatic(cg.p(RubyHash.class), "newHash", cg.sig(
0984:                        RubyHash.class, cg.params(Ruby.class)));
0985:            }
0986:
0987:            public void createNewHash(Object elements, ArrayCallback callback,
0988:                    int keyCount) {
0989:                SkinnyMethodAdapter mv = getMethodAdapter();
0990:
0991:                loadRuntime();
0992:
0993:                // create a new hashmap
0994:                mv.newobj(cg.p(HashMap.class));
0995:                mv.dup();
0996:                mv.invokespecial(cg.p(HashMap.class), "<init>", cg
0997:                        .sig(Void.TYPE));
0998:
0999:                for (int i = 0; i < keyCount; i++) {
1000:                    mv.dup();
1001:                    callback.nextValue(this , elements, i);
1002:                    mv.invokevirtual(cg.p(HashMap.class), "put", cg
1003:                            .sig(Object.class, cg.params(Object.class,
1004:                                    Object.class)));
1005:                    mv.pop();
1006:                }
1007:
1008:                loadNil();
1009:                mv.invokestatic(cg.p(RubyHash.class), "newHash", cg.sig(
1010:                        RubyHash.class, cg.params(Ruby.class, Map.class,
1011:                                IRubyObject.class)));
1012:            }
1013:
1014:            public void createNewRange(boolean isExclusive) {
1015:                SkinnyMethodAdapter mv = getMethodAdapter();
1016:
1017:                loadRuntime();
1018:
1019:                mv.dup_x2();
1020:                mv.pop();
1021:
1022:                mv.ldc(new Boolean(isExclusive));
1023:
1024:                mv.invokestatic(cg.p(RubyRange.class), "newRange", cg.sig(
1025:                        RubyRange.class, cg.params(Ruby.class,
1026:                                IRubyObject.class, IRubyObject.class,
1027:                                Boolean.TYPE)));
1028:            }
1029:
1030:            /**
1031:             * Invoke IRubyObject.isTrue
1032:             */
1033:            private void isTrue() {
1034:                invokeIRubyObject("isTrue", cg.sig(Boolean.TYPE));
1035:            }
1036:
1037:            public void performBooleanBranch(BranchCallback trueBranch,
1038:                    BranchCallback falseBranch) {
1039:                Label afterJmp = new Label();
1040:                Label falseJmp = new Label();
1041:
1042:                SkinnyMethodAdapter mv = getMethodAdapter();
1043:
1044:                // call isTrue on the result
1045:                isTrue();
1046:
1047:                mv.ifeq(falseJmp); // EQ == 0 (i.e. false)
1048:                trueBranch.branch(this );
1049:                mv.go_to(afterJmp);
1050:
1051:                // FIXME: optimize for cases where we have no false branch
1052:                mv.label(falseJmp);
1053:                falseBranch.branch(this );
1054:
1055:                mv.label(afterJmp);
1056:            }
1057:
1058:            public void performLogicalAnd(BranchCallback longBranch) {
1059:                Label afterJmp = new Label();
1060:                Label falseJmp = new Label();
1061:
1062:                SkinnyMethodAdapter mv = getMethodAdapter();
1063:
1064:                // dup it since we need to return appropriately if it's false
1065:                mv.dup();
1066:
1067:                // call isTrue on the result
1068:                isTrue();
1069:
1070:                mv.ifeq(falseJmp); // EQ == 0 (i.e. false)
1071:                // pop the extra result and replace with the send part of the AND
1072:                mv.pop();
1073:                longBranch.branch(this );
1074:                mv.label(falseJmp);
1075:            }
1076:
1077:            public void performLogicalOr(BranchCallback longBranch) {
1078:                Label afterJmp = new Label();
1079:                Label falseJmp = new Label();
1080:
1081:                SkinnyMethodAdapter mv = getMethodAdapter();
1082:
1083:                // dup it since we need to return appropriately if it's false
1084:                mv.dup();
1085:
1086:                // call isTrue on the result
1087:                isTrue();
1088:
1089:                mv.ifne(falseJmp); // EQ == 0 (i.e. false)
1090:                // pop the extra result and replace with the send part of the AND
1091:                mv.pop();
1092:                longBranch.branch(this );
1093:                mv.label(falseJmp);
1094:            }
1095:
1096:            public void performBooleanLoop(BranchCallback condition,
1097:                    BranchCallback body, boolean checkFirst) {
1098:                // FIXME: handle next/continue, break, etc
1099:                SkinnyMethodAdapter mv = getMethodAdapter();
1100:
1101:                Label tryBegin = new Label();
1102:                Label tryEnd = new Label();
1103:                Label tryCatch = new Label();
1104:
1105:                mv.trycatch(tryBegin, tryEnd, tryCatch, cg
1106:                        .p(JumpException.class));
1107:
1108:                mv.label(tryBegin);
1109:                {
1110:                    Label endJmp = new Label();
1111:                    if (checkFirst) {
1112:                        // calculate condition
1113:                        condition.branch(this );
1114:                        // call isTrue on the result
1115:                        isTrue();
1116:
1117:                        mv.ifeq(endJmp); // EQ == 0 (i.e. false)
1118:                    }
1119:
1120:                    Label topJmp = new Label();
1121:
1122:                    mv.label(topJmp);
1123:
1124:                    body.branch(this );
1125:
1126:                    // clear result after each loop
1127:                    mv.pop();
1128:
1129:                    // calculate condition
1130:                    condition.branch(this );
1131:                    // call isTrue on the result
1132:                    isTrue();
1133:
1134:                    mv.ifne(topJmp); // NE == nonzero (i.e. true)
1135:
1136:                    if (checkFirst) {
1137:                        mv.label(endJmp);
1138:                    }
1139:                }
1140:
1141:                mv.label(tryEnd);
1142:
1143:                // no physical break, terminate loop and skip catch block
1144:                Label normalBreak = new Label();
1145:                mv.go_to(normalBreak);
1146:
1147:                mv.label(tryCatch);
1148:                {
1149:                    mv.dup();
1150:                    mv.invokevirtual(cg.p(JumpException.class), "getJumpType",
1151:                            cg.sig(JumpException.JumpType.class));
1152:                    mv.invokevirtual(cg.p(JumpException.JumpType.class),
1153:                            "getTypeId", cg.sig(Integer.TYPE));
1154:
1155:                    Label tryDefault = new Label();
1156:                    Label breakLabel = new Label();
1157:
1158:                    mv.lookupswitch(tryDefault,
1159:                            new int[] { JumpException.JumpType.BREAK },
1160:                            new Label[] { breakLabel });
1161:
1162:                    // default is to just re-throw unhandled exception
1163:                    mv.label(tryDefault);
1164:                    mv.athrow();
1165:
1166:                    // break just terminates the loop normally, unless it's a block break...
1167:                    mv.label(breakLabel);
1168:
1169:                    // JRUBY-530 behavior
1170:                    mv.dup();
1171:                    mv.invokevirtual(cg.p(JumpException.class), "getTarget", cg
1172:                            .sig(Object.class));
1173:                    loadClosure();
1174:                    Label notBlockBreak = new Label();
1175:                    mv.if_acmpne(notBlockBreak);
1176:                    mv.dup();
1177:                    mv.aconst_null();
1178:                    mv.invokevirtual(cg.p(JumpException.class), "setTarget", cg
1179:                            .sig(Void.TYPE, cg.params(Object.class)));
1180:                    mv.athrow();
1181:
1182:                    mv.label(notBlockBreak);
1183:                    // target is not == closure, normal loop exit, pop remaining exception object
1184:                    mv.pop();
1185:                }
1186:
1187:                mv.label(normalBreak);
1188:                loadNil();
1189:            }
1190:
1191:            public void performReturn() {
1192:                if (isCompilingClosure) {
1193:                    throw new NotCompilableException(
1194:                            "Can't compile non-local return");
1195:                }
1196:
1197:                // otherwise, just do a local return
1198:                SkinnyMethodAdapter mv = getMethodAdapter();
1199:                mv.areturn();
1200:            }
1201:
1202:            public void createNewClosure(StaticScope scope, int arity,
1203:                    ClosureCallback body, ClosureCallback args) {
1204:                // FIXME: This isn't quite done yet; waiting to have full support for passing closures so we can test it
1205:                ClassVisitor cv = getClassVisitor();
1206:                SkinnyMethodAdapter method;
1207:
1208:                String closureMethodName = "closure" + ++innerIndex;
1209:                String closureFieldName = "_" + closureMethodName;
1210:
1211:                // declare the field
1212:                cv.visitField(ACC_PRIVATE | ACC_STATIC, closureFieldName, cg
1213:                        .ci(CompiledBlockCallback.class), null, null);
1214:
1215:                ////////////////////////////
1216:                // closure implementation
1217:                method = new SkinnyMethodAdapter(cv.visitMethod(ACC_PUBLIC
1218:                        | ACC_STATIC, closureMethodName, CLOSURE_SIGNATURE,
1219:                        null, null));
1220:
1221:                // FIXME: I don't like this pre/post state management.
1222:                boolean previousIsCompilingClosure = isCompilingClosure;
1223:                isCompilingClosure = true;
1224:
1225:                pushMethodAdapter(method);
1226:
1227:                method.start();
1228:
1229:                // store the local vars in a local variable
1230:                loadThreadContext();
1231:                invokeThreadContext("getCurrentScope", cg
1232:                        .sig(DynamicScope.class));
1233:                method.dup();
1234:                method.astore(LOCAL_VARS_INDEX);
1235:                method.invokevirtual(cg.p(DynamicScope.class), "getValues", cg
1236:                        .sig(IRubyObject[].class));
1237:                method.astore(SCOPE_INDEX);
1238:
1239:                // set up a local IRuby variable
1240:                method.aload(THREADCONTEXT_INDEX);
1241:                invokeThreadContext("getRuntime", cg.sig(Ruby.class));
1242:                method.astore(RUNTIME_INDEX);
1243:
1244:                // set up block arguments
1245:                args.compile(this );
1246:
1247:                // start of scoping for closure's vars
1248:                Label start = new Label();
1249:                method.label(start);
1250:
1251:                // visit the body of the closure
1252:                body.compile(this );
1253:
1254:                method.areturn();
1255:
1256:                // end of scoping for closure's vars
1257:                Label end = new Label();
1258:                method.label(end);
1259:                method.end();
1260:
1261:                popMethodAdapter();
1262:
1263:                // FIXME: I don't like this pre/post state management.
1264:                isCompilingClosure = previousIsCompilingClosure;
1265:
1266:                method = getMethodAdapter();
1267:
1268:                // Done with closure compilation
1269:                /////////////////////////////////////////////////////////////////////////////
1270:
1271:                // Now, store a compiled block object somewhere we can access it in the future
1272:
1273:                // in current method, load the field to see if we've created a BlockCallback yet
1274:                method.getstatic(classname, closureFieldName, cg
1275:                        .ci(CompiledBlockCallback.class));
1276:                Label alreadyCreated = new Label();
1277:                method.ifnonnull(alreadyCreated);
1278:
1279:                // no callback, construct it
1280:                getCallbackFactory();
1281:
1282:                method.ldc(closureMethodName);
1283:                method.invokevirtual(cg.p(CallbackFactory.class),
1284:                        "getBlockCallback", cg.sig(CompiledBlockCallback.class,
1285:                                cg.params(String.class)));
1286:                method.putstatic(classname, closureFieldName, cg
1287:                        .ci(CompiledBlockCallback.class));
1288:
1289:                method.label(alreadyCreated);
1290:
1291:                // Construct the block for passing to the target method
1292:                loadThreadContext();
1293:                loadSelf();
1294:                method.ldc(new Integer(arity));
1295:
1296:                buildStaticScopeNames(method, scope);
1297:
1298:                method.getstatic(classname, closureFieldName, cg
1299:                        .ci(CompiledBlockCallback.class));
1300:
1301:                invokeUtilityMethod("createBlock", cg.sig(CompiledBlock.class,
1302:                        cg.params(ThreadContext.class, IRubyObject.class,
1303:                                Integer.TYPE, String[].class,
1304:                                CompiledBlockCallback.class)));
1305:            }
1306:
1307:            private void buildStaticScopeNames(SkinnyMethodAdapter method,
1308:                    StaticScope scope) {
1309:                // construct static scope list of names
1310:                method.ldc(new Integer(scope.getNumberOfVariables()));
1311:                method.anewarray(cg.p(String.class));
1312:                for (int i = 0; i < scope.getNumberOfVariables(); i++) {
1313:                    method.dup();
1314:                    method.ldc(new Integer(i));
1315:                    method.ldc(scope.getVariables()[i]);
1316:                    method.arraystore();
1317:                }
1318:            }
1319:
1320:            /**
1321:             * This is for utility methods used by the compiler, to reduce the amount of code generation 
1322:             * necessary.  All of these live in CompilerHelpers.
1323:             */
1324:            private void invokeUtilityMethod(String methodName, String signature) {
1325:                getMethodAdapter().invokestatic(cg.p(CompilerHelpers.class),
1326:                        methodName, signature);
1327:            }
1328:
1329:            private void invokeThreadContext(String methodName, String signature) {
1330:                SkinnyMethodAdapter mv = getMethodAdapter();
1331:                mv.invokevirtual(THREADCONTEXT, methodName, signature);
1332:            }
1333:
1334:            private void invokeIRuby(String methodName, String signature) {
1335:                SkinnyMethodAdapter mv = getMethodAdapter();
1336:                mv.invokevirtual(RUBY, methodName, signature);
1337:            }
1338:
1339:            private void getCallbackFactory() {
1340:                SkinnyMethodAdapter mv = getMethodAdapter();
1341:                loadRuntime();
1342:                getCompiledClass();
1343:                mv.dup();
1344:                mv.invokevirtual(cg.p(Class.class), "getClassLoader", cg
1345:                        .sig(ClassLoader.class));
1346:                mv.invokestatic(cg.p(CallbackFactory.class), "createFactory",
1347:                        cg.sig(CallbackFactory.class, cg.params(Ruby.class,
1348:                                Class.class, ClassLoader.class)));
1349:            }
1350:
1351:            private void getCompiledClass() {
1352:                SkinnyMethodAdapter mv = getMethodAdapter();
1353:                mv.getstatic(classname, "$class", cg.ci(Class.class));
1354:            }
1355:
1356:            private void getRubyClass() {
1357:                loadSelf();
1358:                // FIXME: This doesn't seem *quite* right. If actually within a class...end, is self.getMetaClass the correct class? should be self, no?
1359:                invokeIRubyObject("getMetaClass", cg.sig(RubyClass.class));
1360:            }
1361:
1362:            private void println() {
1363:                SkinnyMethodAdapter mv = getMethodAdapter();
1364:
1365:                mv.dup();
1366:                mv.getstatic(cg.p(System.class), "out", cg
1367:                        .ci(PrintStream.class));
1368:                mv.swap();
1369:
1370:                mv.invokevirtual(cg.p(PrintStream.class), "println", cg.sig(
1371:                        Void.TYPE, cg.params(Object.class)));
1372:            }
1373:
1374:            public void defineAlias(String newName, String oldName) {
1375:                getRubyClass();
1376:                getMethodAdapter().ldc(newName);
1377:                getMethodAdapter().ldc(oldName);
1378:                getMethodAdapter().invokevirtual(
1379:                        cg.p(RubyModule.class),
1380:                        "defineAlias",
1381:                        cg
1382:                                .sig(Void.TYPE, cg.params(String.class,
1383:                                        String.class)));
1384:                loadNil();
1385:                // TODO: should call method_added, and possibly push nil.
1386:            }
1387:
1388:            public void defineNewMethod(String name, StaticScope scope,
1389:                    ClosureCallback body, ClosureCallback args) {
1390:                if (isCompilingClosure) {
1391:                    throw new NotCompilableException(
1392:                            "Can't compile def within closure yet");
1393:                }
1394:
1395:                // TODO: build arg list based on number of args, optionals, etc
1396:                ++methodIndex;
1397:                String methodName = cg.cleanJavaIdentifier(name) + "__"
1398:                        + methodIndex;
1399:
1400:                beginMethod(methodName, args);
1401:
1402:                SkinnyMethodAdapter mv = getMethodAdapter();
1403:
1404:                // callbacks to fill in method body
1405:                body.compile(this );
1406:
1407:                endMethod(mv);
1408:
1409:                // return to previous method
1410:                mv = getMethodAdapter();
1411:
1412:                // prepare to call "def" utility method to handle def logic
1413:                loadThreadContext();
1414:
1415:                loadVisibility();
1416:
1417:                loadSelf();
1418:
1419:                // load the class we're creating, for binding purposes
1420:                getCompiledClass();
1421:
1422:                mv.ldc(name);
1423:
1424:                mv.ldc(methodName);
1425:
1426:                buildStaticScopeNames(mv, scope);
1427:
1428:                mv.ldc(new Integer(0));
1429:
1430:                invokeUtilityMethod("def", cg.sig(IRubyObject.class, cg.params(
1431:                        ThreadContext.class, Visibility.class,
1432:                        IRubyObject.class, Class.class, String.class,
1433:                        String.class, String[].class, Integer.TYPE)));
1434:            }
1435:
1436:            public void processRequiredArgs(Arity arity, int totalArgs) {
1437:                SkinnyMethodAdapter newMethod = getMethodAdapter();
1438:
1439:                // check arity
1440:                newMethod.ldc(new Integer(arity.getValue()));
1441:                newMethod.invokestatic(cg.p(Arity.class), "createArity", cg
1442:                        .sig(Arity.class, cg.params(Integer.TYPE)));
1443:                loadRuntime();
1444:                newMethod.aload(ARGS_INDEX);
1445:                newMethod.invokevirtual(cg.p(Arity.class), "checkArity", cg
1446:                        .sig(Void.TYPE, cg.params(Ruby.class,
1447:                                IRubyObject[].class)));
1448:
1449:                // optional has different checks for size
1450:                if (!arity.isFixed()) {
1451:                    loadRuntime();
1452:                    newMethod.aload(ARGS_INDEX);
1453:                    newMethod.arraylength();
1454:                    newMethod.ldc(new Integer(totalArgs));
1455:                    invokeUtilityMethod("raiseArgumentError", cg.sig(Void.TYPE,
1456:                            cg.params(Ruby.class, Integer.TYPE, Integer.TYPE)));
1457:                }
1458:
1459:                // arraycopy all arguments into local vars array
1460:                Label noArgs = new Label();
1461:                newMethod.aload(ARGS_INDEX);
1462:                newMethod.ifnull(noArgs);
1463:                newMethod.aload(ARGS_INDEX);
1464:                newMethod.arraylength();
1465:                newMethod.ifeq(noArgs);
1466:                newMethod.aload(LOCAL_VARS_INDEX);
1467:                newMethod.aload(ARGS_INDEX);
1468:                newMethod.dup();
1469:                newMethod.arraylength();
1470:                newMethod.invokevirtual(cg.p(DynamicScope.class),
1471:                        "setArgValues", cg.sig(Void.TYPE, cg.params(
1472:                                IRubyObject[].class, Integer.TYPE)));
1473:                newMethod.label(noArgs);
1474:
1475:                // push down the argument count of this method
1476:                pushArity(arity);
1477:            }
1478:
1479:            public void assignOptionalArgs(Object object,
1480:                    int expectedArgsCount, int size, ArrayCallback optEval) {
1481:                SkinnyMethodAdapter newMethod = getMethodAdapter();
1482:
1483:                // NOTE: By the time we're here, arity should have already been checked. We proceed without boundschecking.
1484:
1485:                // opt args are handled with a switch; the key is how many args we have coming in, and the cases are
1486:                // each opt arg index. The cases fall-through, so remaining opt args are handled.
1487:                newMethod.aload(ARGS_INDEX);
1488:                newMethod.arraylength();
1489:
1490:                Label defaultLabel = new Label();
1491:                Label[] labels = new Label[size];
1492:
1493:                for (int i = 0; i < size; i++) {
1494:                    labels[i] = new Label();
1495:                }
1496:
1497:                newMethod.tableswitch(expectedArgsCount, expectedArgsCount
1498:                        + size - 1, defaultLabel, labels);
1499:
1500:                for (int i = 0; i < size; i++) {
1501:                    newMethod.label(labels[i]);
1502:                    optEval.nextValue(this , object, i);
1503:                    newMethod.pop();
1504:                }
1505:
1506:                newMethod.label(defaultLabel);
1507:            }
1508:
1509:            public void loadFalse() {
1510:                loadRuntime();
1511:                invokeIRuby("getFalse", cg.sig(RubyBoolean.class));
1512:            }
1513:
1514:            public void loadTrue() {
1515:                loadRuntime();
1516:                invokeIRuby("getTrue", cg.sig(RubyBoolean.class));
1517:            }
1518:
1519:            public void retrieveInstanceVariable(String name) {
1520:                loadSelf();
1521:
1522:                SkinnyMethodAdapter mv = getMethodAdapter();
1523:
1524:                mv.ldc(name);
1525:                invokeIRubyObject("getInstanceVariable", cg.sig(
1526:                        IRubyObject.class, cg.params(String.class)));
1527:
1528:                // check if it's null; if so, load nil
1529:                mv.dup();
1530:                Label notNull = new Label();
1531:                mv.ifnonnull(notNull);
1532:
1533:                // pop the dup'ed null
1534:                mv.pop();
1535:                // replace it with nil
1536:                loadNil();
1537:
1538:                mv.label(notNull);
1539:            }
1540:
1541:            public void assignInstanceVariable(String name) {
1542:                SkinnyMethodAdapter mv = getMethodAdapter();
1543:
1544:                loadSelf();
1545:                mv.swap();
1546:
1547:                mv.ldc(name);
1548:                mv.swap();
1549:
1550:                invokeIRubyObject("setInstanceVariable", cg.sig(
1551:                        IRubyObject.class, cg.params(String.class,
1552:                                IRubyObject.class)));
1553:            }
1554:
1555:            public void assignInstanceVariableBlockArg(int argIndex, String name) {
1556:                SkinnyMethodAdapter mv = getMethodAdapter();
1557:
1558:                loadSelf();
1559:                mv.ldc(name);
1560:
1561:                mv.aload(ARGS_INDEX);
1562:                mv.ldc(new Integer(argIndex));
1563:                mv.arrayload();
1564:
1565:                invokeIRubyObject("setInstanceVariable", cg.sig(
1566:                        IRubyObject.class, cg.params(String.class,
1567:                                IRubyObject.class)));
1568:            }
1569:
1570:            public void retrieveGlobalVariable(String name) {
1571:                loadRuntime();
1572:
1573:                SkinnyMethodAdapter mv = getMethodAdapter();
1574:
1575:                invokeIRuby("getGlobalVariables", cg.sig(GlobalVariables.class));
1576:                mv.ldc(name);
1577:                mv.invokevirtual(cg.p(GlobalVariables.class), "get", cg.sig(
1578:                        IRubyObject.class, cg.params(String.class)));
1579:            }
1580:
1581:            public void assignGlobalVariable(String name) {
1582:                loadRuntime();
1583:
1584:                SkinnyMethodAdapter mv = getMethodAdapter();
1585:
1586:                invokeIRuby("getGlobalVariables", cg.sig(GlobalVariables.class));
1587:                mv.swap();
1588:                mv.ldc(name);
1589:                mv.swap();
1590:                mv.invokevirtual(cg.p(GlobalVariables.class), "set", cg.sig(
1591:                        IRubyObject.class, cg.params(String.class,
1592:                                IRubyObject.class)));
1593:            }
1594:
1595:            public void assignGlobalVariableBlockArg(int argIndex, String name) {
1596:                loadRuntime();
1597:
1598:                SkinnyMethodAdapter mv = getMethodAdapter();
1599:
1600:                invokeIRuby("getGlobalVariables", cg.sig(GlobalVariables.class));
1601:                mv.ldc(name);
1602:
1603:                mv.aload(ARGS_INDEX);
1604:                mv.ldc(new Integer(argIndex));
1605:                mv.arrayload();
1606:
1607:                mv.invokevirtual(cg.p(GlobalVariables.class), "set", cg.sig(
1608:                        IRubyObject.class, cg.params(String.class,
1609:                                IRubyObject.class)));
1610:            }
1611:
1612:            public void negateCurrentValue() {
1613:                SkinnyMethodAdapter mv = getMethodAdapter();
1614:
1615:                isTrue();
1616:                Label isTrue = new Label();
1617:                Label end = new Label();
1618:                mv.ifne(isTrue);
1619:                loadTrue();
1620:                mv.go_to(end);
1621:                mv.label(isTrue);
1622:                loadFalse();
1623:                mv.label(end);
1624:            }
1625:
1626:            public void splatCurrentValue() {
1627:                SkinnyMethodAdapter method = getMethodAdapter();
1628:
1629:                method
1630:                        .invokestatic(cg.p(EvaluationState.class),
1631:                                "splatValue", cg.sig(IRubyObject.class, cg
1632:                                        .params(IRubyObject.class)));
1633:            }
1634:
1635:            public void singlifySplattedValue() {
1636:                SkinnyMethodAdapter method = getMethodAdapter();
1637:                method
1638:                        .invokestatic(cg.p(EvaluationState.class),
1639:                                "aValueSplat", cg.sig(IRubyObject.class, cg
1640:                                        .params(IRubyObject.class)));
1641:            }
1642:
1643:            public void ensureRubyArray() {
1644:                invokeUtilityMethod("ensureRubyArray", cg.sig(RubyArray.class,
1645:                        cg.params(IRubyObject.class)));
1646:            }
1647:
1648:            public void forEachInValueArray(int start, int count,
1649:                    Object source, ArrayCallback callback) {
1650:                SkinnyMethodAdapter method = getMethodAdapter();
1651:
1652:                Label noMoreArrayElements = new Label();
1653:                for (; start < count; start++) {
1654:                    // confirm we're not past the end of the array
1655:                    method.dup(); // dup the original array object
1656:                    method.invokevirtual(cg.p(RubyArray.class), "getLength", cg
1657:                            .sig(Integer.TYPE, cg.params()));
1658:                    method.ldc(new Integer(start));
1659:                    method.ifle(noMoreArrayElements); // if length <= start, end loop
1660:
1661:                    // extract item from array
1662:                    method.dup(); // dup the original array object
1663:                    method.ldc(new Integer(start)); // index for the item
1664:                    method.invokevirtual(cg.p(RubyArray.class), "entry", cg
1665:                            .sig(IRubyObject.class, cg.params(Long.TYPE))); // extract item
1666:                    callback.nextValue(this , source, start);
1667:                }
1668:                method.label(noMoreArrayElements);
1669:            }
1670:
1671:            public void loadInteger(int value) {
1672:                throw new UnsupportedOperationException("Not supported yet.");
1673:            }
1674:
1675:            public void performGEBranch(BranchCallback trueBranch,
1676:                    BranchCallback falseBranch) {
1677:                throw new UnsupportedOperationException("Not supported yet.");
1678:            }
1679:
1680:            public void performGTBranch(BranchCallback trueBranch,
1681:                    BranchCallback falseBranch) {
1682:                throw new UnsupportedOperationException("Not supported yet.");
1683:            }
1684:
1685:            public void performLEBranch(BranchCallback trueBranch,
1686:                    BranchCallback falseBranch) {
1687:                throw new UnsupportedOperationException("Not supported yet.");
1688:            }
1689:
1690:            public void performLTBranch(BranchCallback trueBranch,
1691:                    BranchCallback falseBranch) {
1692:                throw new UnsupportedOperationException("Not supported yet.");
1693:            }
1694:
1695:            public void loadRubyArraySize() {
1696:                throw new UnsupportedOperationException("Not supported yet.");
1697:            }
1698:
1699:            public void issueBreakEvent() {
1700:                SkinnyMethodAdapter mv = getMethodAdapter();
1701:
1702:                mv.newobj(cg.p(JumpException.class));
1703:                mv.dup();
1704:                mv.getstatic(cg.p(JumpException.JumpType.class), "BreakJump",
1705:                        cg.ci(JumpException.JumpType.class));
1706:                mv.invokespecial(cg.p(JumpException.class), "<init>", cg.sig(
1707:                        Void.TYPE, cg.params(JumpException.JumpType.class)));
1708:
1709:                // set result into jump exception
1710:                mv.dup_x1();
1711:                mv.swap();
1712:                mv.invokevirtual(cg.p(JumpException.class), "setValue", cg.sig(
1713:                        Void.TYPE, cg.params(Object.class)));
1714:
1715:                mv.athrow();
1716:            }
1717:
1718:            public void asString() {
1719:                SkinnyMethodAdapter mv = getMethodAdapter();
1720:                mv.invokeinterface(cg.p(IRubyObject.class), "asString", cg.sig(
1721:                        RubyString.class, cg.params()));
1722:            }
1723:
1724:            public void nthRef(int match) {
1725:                SkinnyMethodAdapter mv = getMethodAdapter();
1726:
1727:                mv.ldc(new Integer(match));
1728:                loadThreadContext();
1729:                invokeThreadContext("getBackref", cg.sig(IRubyObject.class, cg
1730:                        .params()));
1731:                mv.invokestatic(cg.p(RubyRegexp.class), "nth_match", cg.sig(
1732:                        IRubyObject.class, cg.params(Integer.TYPE,
1733:                                IRubyObject.class)));
1734:            }
1735:
1736:            public void match() {
1737:                SkinnyMethodAdapter mv = getMethodAdapter();
1738:                mv.invokevirtual(cg.p(RubyRegexp.class), "match2", cg.sig(
1739:                        IRubyObject.class, cg.params()));
1740:            }
1741:
1742:            public void match2() {
1743:                SkinnyMethodAdapter mv = getMethodAdapter();
1744:                mv.invokevirtual(cg.p(RubyRegexp.class), "match", cg.sig(
1745:                        IRubyObject.class, cg.params(IRubyObject.class)));
1746:            }
1747:
1748:            public void match3() {
1749:                SkinnyMethodAdapter mv = getMethodAdapter();
1750:
1751:                mv.dup();
1752:                mv.visitTypeInsn(INSTANCEOF, cg.p(RubyString.class));
1753:
1754:                Label l0 = new Label();
1755:                mv.visitJumpInsn(IFEQ, l0);
1756:
1757:                mv.invokevirtual(cg.p(RubyRegexp.class), "match", cg.sig(
1758:                        IRubyObject.class, cg.params(IRubyObject.class)));
1759:
1760:                Label l1 = new Label();
1761:                mv.visitJumpInsn(GOTO, l1);
1762:                mv.visitLabel(l0);
1763:
1764:                mv.swap();
1765:                loadThreadContext();
1766:                mv.swap();
1767:                mv.ldc("=~");
1768:                mv.swap();
1769:
1770:                mv.invokeinterface(cg.p(IRubyObject.class), "callMethod", cg
1771:                        .sig(IRubyObject.class, cg.params(ThreadContext.class,
1772:                                String.class, IRubyObject.class)));
1773:                mv.visitLabel(l1);
1774:            }
1775:
1776:            private int constants = 0;
1777:
1778:            private String getNewConstant(String type, String name_prefix) {
1779:                ClassVisitor cv = getClassVisitor();
1780:
1781:                String realName;
1782:                synchronized (this ) {
1783:                    realName = name_prefix + constants++;
1784:                }
1785:
1786:                // declare the field
1787:                cv.visitField(ACC_PRIVATE | ACC_STATIC, realName, type, null,
1788:                        null).visitEnd();
1789:                return realName;
1790:            }
1791:
1792:            public void createNewRegexp(final ByteList value,
1793:                    final int options, final String lang) {
1794:                SkinnyMethodAdapter mv = getMethodAdapter();
1795:                String name = getNewConstant(cg.ci(Pattern.class),
1796:                        "literal_re_");
1797:                String name_flags = getNewConstant(cg.ci(Integer.TYPE),
1798:                        "literal_re_flags_");
1799:
1800:                loadRuntime();
1801:
1802:                // load string, for Regexp#source and Regexp#inspect
1803:                String regexpString = null;
1804:                if ((options & ReOptions.RE_UNICODE) > 0) {
1805:                    regexpString = value.toUtf8String();
1806:                } else {
1807:                    regexpString = value.toString();
1808:                }
1809:                mv.ldc(regexpString);
1810:
1811:                // in current method, load the field to see if we've created a Pattern yet
1812:
1813:                mv.visitFieldInsn(GETSTATIC, classname, name, cg
1814:                        .ci(Pattern.class));
1815:                mv.dup();
1816:
1817:                Label alreadyCreated = new Label();
1818:                mv.ifnonnull(alreadyCreated);
1819:                mv.pop();
1820:                mv.ldc(new Integer(options));
1821:                invokeUtilityMethod("regexpLiteralFlags", cg.sig(Integer.TYPE,
1822:                        cg.params(Integer.TYPE)));
1823:                mv.visitFieldInsn(PUTSTATIC, classname, name_flags, cg
1824:                        .ci(Integer.TYPE));
1825:
1826:                loadRuntime();
1827:                mv.ldc(regexpString);
1828:                mv.ldc(new Integer(options));
1829:                invokeUtilityMethod("regexpLiteral", cg.sig(Pattern.class, cg
1830:                        .params(Ruby.class, String.class, Integer.TYPE)));
1831:                mv.dup();
1832:
1833:                mv.visitFieldInsn(PUTSTATIC, classname, name, cg
1834:                        .ci(Pattern.class));
1835:
1836:                mv.label(alreadyCreated);
1837:
1838:                mv.visitFieldInsn(GETSTATIC, classname, name_flags, cg
1839:                        .ci(Integer.TYPE));
1840:                if (null == lang) {
1841:                    mv.aconst_null();
1842:                } else {
1843:                    mv.ldc(lang);
1844:                }
1845:
1846:                mv.invokestatic(cg.p(RubyRegexp.class), "newRegexp", cg.sig(
1847:                        RubyRegexp.class, cg.params(Ruby.class, String.class,
1848:                                Pattern.class, Integer.TYPE, String.class)));
1849:            }
1850:
1851:            public void defineClass(String name, StaticScope staticScope,
1852:                    ClosureCallback super Callback,
1853:                    ClosureCallback pathCallback, ClosureCallback bodyCallback) {
1854:                // TODO: build arg list based on number of args, optionals, etc
1855:                ++methodIndex;
1856:                String methodName = "rubyclass__"
1857:                        + cg.cleanJavaIdentifier(name) + "__" + methodIndex;
1858:
1859:                beginMethod(methodName, null);
1860:
1861:                SkinnyMethodAdapter mv = getMethodAdapter();
1862:
1863:                // class def bodies default to public visibility
1864:                mv.getstatic(cg.p(Visibility.class), "PUBLIC", cg
1865:                        .ci(Visibility.class));
1866:                mv.astore(VISIBILITY_INDEX);
1867:
1868:                // Here starts the logic for the class definition
1869:                loadRuntime();
1870:
1871:                super Callback.compile(this );
1872:
1873:                invokeUtilityMethod("prepareSuperClass", cg.sig(
1874:                        RubyClass.class, cg.params(Ruby.class,
1875:                                IRubyObject.class)));
1876:
1877:                loadThreadContext();
1878:
1879:                pathCallback.compile(this );
1880:
1881:                invokeUtilityMethod("prepareClassNamespace", cg.sig(
1882:                        RubyModule.class, cg.params(ThreadContext.class,
1883:                                IRubyObject.class)));
1884:
1885:                mv.swap();
1886:
1887:                mv.ldc(name);
1888:
1889:                mv.swap();
1890:
1891:                mv.invokevirtual(cg.p(RubyModule.class),
1892:                        "defineOrGetClassUnder", cg.sig(RubyClass.class, cg
1893:                                .params(String.class, RubyClass.class)));
1894:
1895:                // set self to the class
1896:                mv.dup();
1897:                mv.astore(SELF_INDEX);
1898:
1899:                // CLASS BODY
1900:                loadThreadContext();
1901:                mv.swap();
1902:
1903:                // FIXME: this should be in a try/finally
1904:                invokeThreadContext("preCompiledClass", cg.sig(Void.TYPE, cg
1905:                        .params(RubyModule.class)));
1906:
1907:                bodyCallback.compile(this );
1908:
1909:                loadThreadContext();
1910:                invokeThreadContext("postCompiledClass", cg.sig(Void.TYPE, cg
1911:                        .params()));
1912:
1913:                endMethod(mv);
1914:
1915:                // return to previous method
1916:                mv = getMethodAdapter();
1917:
1918:                // prepare to call class definition method
1919:                loadThreadContext();
1920:                loadSelf();
1921:                mv.getstatic(cg.p(IRubyObject.class), "NULL_ARRAY", cg
1922:                        .ci(IRubyObject[].class));
1923:                mv.getstatic(cg.p(Block.class), "NULL_BLOCK", cg
1924:                        .ci(Block.class));
1925:
1926:                mv.invokestatic(classname, methodName, METHOD_SIGNATURE);
1927:            }
1928:
1929:            public void defineModule(String name, StaticScope staticScope,
1930:                    ClosureCallback pathCallback, ClosureCallback bodyCallback) {
1931:                // TODO: build arg list based on number of args, optionals, etc
1932:                ++methodIndex;
1933:                String methodName = "rubymodule__"
1934:                        + cg.cleanJavaIdentifier(name) + "__" + methodIndex;
1935:
1936:                beginMethod(methodName, null);
1937:
1938:                SkinnyMethodAdapter mv = getMethodAdapter();
1939:
1940:                // module def bodies default to public visibility
1941:                mv.getstatic(cg.p(Visibility.class), "PUBLIC", cg
1942:                        .ci(Visibility.class));
1943:                mv.astore(VISIBILITY_INDEX);
1944:
1945:                // Here starts the logic for the module definition
1946:                loadThreadContext();
1947:
1948:                pathCallback.compile(this );
1949:
1950:                invokeUtilityMethod("prepareClassNamespace", cg.sig(
1951:                        RubyModule.class, cg.params(ThreadContext.class,
1952:                                IRubyObject.class)));
1953:
1954:                mv.ldc(name);
1955:
1956:                mv.invokevirtual(cg.p(RubyModule.class), "defineModuleUnder",
1957:                        cg.sig(RubyModule.class, cg.params(String.class)));
1958:
1959:                // set self to the module
1960:                mv.dup();
1961:                mv.astore(SELF_INDEX);
1962:
1963:                // MODULE BODY
1964:                loadThreadContext();
1965:                mv.swap();
1966:
1967:                // FIXME: this should be in a try/finally
1968:                invokeThreadContext("preCompiledClass", cg.sig(Void.TYPE, cg
1969:                        .params(RubyModule.class)));
1970:
1971:                bodyCallback.compile(this );
1972:
1973:                loadThreadContext();
1974:                invokeThreadContext("postCompiledClass", cg.sig(Void.TYPE, cg
1975:                        .params()));
1976:
1977:                endMethod(mv);
1978:
1979:                // return to previous method
1980:                mv = getMethodAdapter();
1981:
1982:                // prepare to call class definition method
1983:                loadThreadContext();
1984:                loadSelf();
1985:                mv.getstatic(cg.p(IRubyObject.class), "NULL_ARRAY", cg
1986:                        .ci(IRubyObject[].class));
1987:                mv.getstatic(cg.p(Block.class), "NULL_BLOCK", cg
1988:                        .ci(Block.class));
1989:
1990:                mv.invokestatic(classname, methodName, METHOD_SIGNATURE);
1991:            }
1992:
1993:            public void pollThreadEvents() {
1994:                loadThreadContext();
1995:                invokeThreadContext("pollThreadEvents", cg.sig(Void.TYPE));
1996:            }
1997:
1998:            private void nullToNil() {
1999:                loadRuntime();
2000:                invokeUtilityMethod("nullToNil", cg.sig(IRubyObject.class, cg
2001:                        .params(IRubyObject.class, Ruby.class)));
2002:            }
2003:
2004:            public void branchIfModule(BranchCallback moduleCallback,
2005:                    BranchCallback notModuleCallback) {
2006:                SkinnyMethodAdapter mv = getMethodAdapter();
2007:                mv.dup();
2008:                mv.visitTypeInsn(INSTANCEOF, cg.p(RubyModule.class));
2009:
2010:                Label falseJmp = new Label();
2011:                Label afterJmp = new Label();
2012:
2013:                mv.ifeq(falseJmp); // EQ == 0 (i.e. false)
2014:
2015:                moduleCallback.branch(this);
2016:
2017:                mv.go_to(afterJmp);
2018:                mv.label(falseJmp);
2019:
2020:                notModuleCallback.branch(this);
2021:
2022:                mv.label(afterJmp);
2023:            }
2024:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.