KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jruby > compiler > impl > StandardASMCompiler


1 /***** BEGIN LICENSE BLOCK *****
2  * Version: CPL 1.0/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Common Public
5  * License Version 1.0 (the "License"); you may not use this file
6  * except in compliance with the License. You may obtain a copy of
7  * the License at http://www.eclipse.org/legal/cpl-v10.html
8  *
9  * Software distributed under the License is distributed on an "AS
10  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11  * implied. See the License for the specific language governing
12  * rights and limitations under the License.
13  *
14  * Copyright (C) 2006 Charles O Nutter <headius@headius.com>
15  *
16  * Alternatively, the contents of this file may be used under the terms of
17  * either of the GNU General Public License Version 2 or later (the "GPL"),
18  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
19  * in which case the provisions of the GPL or the LGPL are applicable instead
20  * of those above. If you wish to allow use of your version of this file only
21  * under the terms of either the GPL or the LGPL, and not to allow others to
22  * use your version of this file under the terms of the CPL, indicate your
23  * decision by deleting the provisions above and replace them with the notice
24  * and other provisions required by the GPL or the LGPL. If you do not delete
25  * the provisions above, a recipient may use your version of this file under
26  * the terms of any one of the CPL, the GPL or the LGPL.
27  ***** END LICENSE BLOCK *****/

28
29 package org.jruby.compiler.impl;
30
31 import java.io.File JavaDoc;
32 import java.io.FileOutputStream JavaDoc;
33 import java.io.IOException JavaDoc;
34 import java.io.PrintStream JavaDoc;
35 import java.util.Stack JavaDoc;
36 import org.jruby.Ruby;
37 import org.jruby.MetaClass;
38 import org.jruby.RubyArray;
39 import org.jruby.RubyBoolean;
40 import org.jruby.RubyClass;
41 import org.jruby.RubyFixnum;
42 import org.jruby.RubyModule;
43 import org.jruby.RubyString;
44 import org.jruby.RubySymbol;
45 import org.jruby.ast.Node;
46 import org.jruby.ast.executable.Script;
47 import org.jruby.compiler.*;
48 import org.jruby.compiler.Compiler;
49 import org.jruby.evaluator.EvaluationState;
50 import org.jruby.exceptions.RaiseException;
51 import org.jruby.internal.runtime.GlobalVariables;
52 import org.jruby.internal.runtime.methods.DynamicMethod;
53 import org.jruby.internal.runtime.methods.WrapperMethod;
54 import org.jruby.lexer.yacc.ISourcePosition;
55 import org.jruby.parser.StaticScope;
56 import org.jruby.runtime.Arity;
57 import org.jruby.runtime.Block;
58 import org.jruby.runtime.CallType;
59 import org.jruby.runtime.CallbackFactory;
60 import org.jruby.runtime.CompiledBlock;
61 import org.jruby.runtime.CompiledBlockCallback;
62 import org.jruby.runtime.MethodFactory;
63 import org.jruby.runtime.MethodIndex;
64 import org.jruby.runtime.ThreadContext;
65 import org.jruby.runtime.Visibility;
66 import org.jruby.runtime.builtin.IRubyObject;
67 import org.jruby.util.ByteList;
68 import org.jruby.util.CodegenUtils;
69 import org.jruby.util.JRubyClassLoader;
70 import org.jruby.util.collections.SinglyLinkedList;
71 import org.objectweb.asm.ClassVisitor;
72 import org.objectweb.asm.ClassWriter;
73 import org.objectweb.asm.Label;
74 import org.objectweb.asm.MethodVisitor;
75 import org.objectweb.asm.Opcodes;
76
77 /**
78  *
79  * @author headius
80  */

81 public class StandardASMCompiler implements Compiler JavaDoc {
82     private static final CodegenUtils cg = CodegenUtils.instance;
83     private static final String JavaDoc THREADCONTEXT = cg.p(ThreadContext.class);
84     private static final String JavaDoc RUBY = cg.p(Ruby.class);
85     private static final String JavaDoc IRUBYOBJECT = cg.p(IRubyObject.class);
86     
87     private static final String JavaDoc METHOD_SIGNATURE =
88             cg.sig(IRubyObject.class, new Class JavaDoc[] { ThreadContext.class, IRubyObject.class, IRubyObject[].class, Block.class });
89     private static final String JavaDoc CLOSURE_SIGNATURE =
90             cg.sig(IRubyObject.class, new Class JavaDoc[] { ThreadContext.class, IRubyObject.class, IRubyObject[].class, Block.class, IRubyObject[][].class });
91     
92     private static final int THREADCONTEXT_INDEX = 0;
93     private static final int SELF_INDEX = 1;
94     private static final int ARGS_INDEX = 2;
95     private static final int CLOSURE_INDEX = 3;
96     private static final int SCOPE_INDEX = 4;
97     private static final int RUNTIME_INDEX = 5;
98     private static final int LOCAL_VARS_INDEX = 6;
99     
100     private Stack JavaDoc methodVisitors = new Stack JavaDoc();
101     private Stack JavaDoc arities = new Stack JavaDoc();
102     private Stack JavaDoc scopeStarts = new Stack JavaDoc();
103     
104     private String JavaDoc classname;
105     private String JavaDoc sourcename;
106     
107     //Map classWriters = new HashMacg.p();
108
private ClassWriter classWriter;
109     ClassWriter currentMultiStub = null;
110     int methodIndex = -1;
111     int multiStubCount = -1;
112     int innerIndex = -1;
113     
114     int lastLine = -1;
115     
116     /** Creates a new instance of StandardCompilerContext */
117     public StandardASMCompiler(String JavaDoc classname, String JavaDoc sourcename) {
118         this.classname = classname;
119         this.sourcename = sourcename;
120     }
121     
122     public StandardASMCompiler(Node node) {
123         // determine new class name based on filename of incoming node
124
// must generate unique classnames for evals, since they could be generated many times in a given run
125
classname = "EVAL" + hashCode();
126         sourcename = "EVAL" + hashCode();
127     }
128     
129     public Class JavaDoc loadClass(Ruby runtime) throws ClassNotFoundException JavaDoc {
130         JRubyClassLoader jcl = runtime.getJRubyClassLoader();
131         
132         jcl.defineClass(cg.c(classname), classWriter.toByteArray());
133         
134         return jcl.loadClass(cg.c(classname));
135     }
136     
137     public void writeClass(File JavaDoc destination) throws IOException JavaDoc {
138         writeClass(classname, destination, classWriter);
139     }
140     
141     private void writeClass(String JavaDoc classname, File JavaDoc destination, ClassWriter writer) throws IOException JavaDoc {
142         String JavaDoc fullname = classname + ".class";
143         String JavaDoc filename = null;
144         String JavaDoc path = null;
145         if (fullname.lastIndexOf("/") == -1) {
146             filename = fullname;
147             path = "";
148         } else {
149             filename = fullname.substring(fullname.lastIndexOf("/") + 1);
150             path = fullname.substring(0, fullname.lastIndexOf("/"));
151         }
152         // create dir if necessary
153
File JavaDoc pathfile = new File JavaDoc(destination, path);
154         pathfile.mkdirs();
155         
156         FileOutputStream JavaDoc out = new FileOutputStream JavaDoc(new File JavaDoc(pathfile, filename));
157         
158         out.write(writer.toByteArray());
159     }
160     
161     public String JavaDoc getClassname() {
162         return classname;
163     }
164     
165     public String JavaDoc getSourcename() {
166         return sourcename;
167     }
168     
169     public ClassVisitor getClassVisitor() {
170         return classWriter;
171     }
172     
173     public MethodVisitor getMethodVisitor() {
174         return (MethodVisitor)methodVisitors.peek();
175     }
176     
177     public MethodVisitor popMethodVisitor() {
178         return (MethodVisitor)methodVisitors.pop();
179     }
180     
181     public void pushMethodVisitor(MethodVisitor mv) {
182         methodVisitors.push(mv);
183     }
184     
185     public int getArity() {
186         return ((Integer JavaDoc)arities.peek()).intValue();
187     }
188     
189     public void pushArity(int arity) {
190         arities.push(new Integer JavaDoc(arity));
191     }
192     
193     public int popArity() {
194         return ((Integer JavaDoc)arities.pop()).intValue();
195     }
196     
197     public void pushScopeStart(Label start) {
198         scopeStarts.push(start);
199     }
200     
201     public Label popScopeStart() {
202         return (Label)scopeStarts.pop();
203     }
204     
205     public void startScript() {
206         classWriter = new ClassWriter(true);
207         
208         // Create the class with the appropriate class name and source file
209
classWriter.visit(Opcodes.V1_2, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, classname, null, cg.p(Object JavaDoc.class), new String JavaDoc[] {cg.p(Script.class)});
210         classWriter.visitSource(sourcename, null);
211         
212         createConstructor();
213     }
214     
215     public void endScript() {
216         // add Script#run impl, used for running this script with a specified threadcontext and self
217
// root method of a script is always in __load__ method
218
String JavaDoc methodName = "__file__";
219         MethodVisitor mv = getClassVisitor().visitMethod(Opcodes.ACC_PUBLIC, "run", METHOD_SIGNATURE, null, null);
220         mv.visitCode();
221         
222         // invoke __file__ with threadcontext, self, args (null), and block (null)
223
// These are all +1 because run is an instance method where others are static
224
mv.visitVarInsn(Opcodes.ALOAD, THREADCONTEXT_INDEX + 1);
225         mv.visitVarInsn(Opcodes.ALOAD, SELF_INDEX + 1);
226         mv.visitVarInsn(Opcodes.ALOAD, ARGS_INDEX + 1);
227         mv.visitVarInsn(Opcodes.ALOAD, CLOSURE_INDEX + 1);
228         
229         mv.visitMethodInsn(Opcodes.INVOKESTATIC, classname, methodName, METHOD_SIGNATURE);
230         mv.visitInsn(Opcodes.ARETURN);
231         mv.visitMaxs(1, 1);
232         mv.visitEnd();
233         
234         // add main impl, used for detached or command-line execution of this script with a new runtime
235
// root method of a script is always in stub0, method0
236
mv = getClassVisitor().visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "main", cg.sig(Void.TYPE, cg.params(String JavaDoc[].class)), null, null);
237         mv.visitCode();
238         
239         // new instance to invoke run against
240
mv.visitTypeInsn(Opcodes.NEW, classname);
241         mv.visitInsn(Opcodes.DUP);
242         mv.visitMethodInsn(Opcodes.INVOKESPECIAL, classname, "<init>", cg.sig(Void.TYPE));
243         
244         // invoke run with threadcontext and topself
245
mv.visitMethodInsn(Opcodes.INVOKESTATIC, cg.p(Ruby.class), "getDefaultInstance", cg.sig(Ruby.class));
246         mv.visitInsn(Opcodes.DUP);
247         
248         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, RUBY, "getCurrentContext", cg.sig(ThreadContext.class));
249         mv.visitInsn(Opcodes.SWAP);
250         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, RUBY, "getTopSelf", cg.sig(IRubyObject.class));
251         mv.visitInsn(Opcodes.ACONST_NULL);
252         mv.visitInsn(Opcodes.ACONST_NULL);
253         
254         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, classname, "run", METHOD_SIGNATURE);
255         mv.visitInsn(Opcodes.RETURN);
256         mv.visitMaxs(1, 1);
257         mv.visitEnd();
258     }
259     
260     private void createConstructor() {
261         ClassVisitor cv = getClassVisitor();
262         
263         MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC, "<init>", cg.sig(Void.TYPE), null, null);
264         mv.visitCode();
265         mv.visitVarInsn(Opcodes.ALOAD, 0);
266         mv.visitMethodInsn(Opcodes.INVOKESPECIAL, cg.p(Object JavaDoc.class), "<init>",
267                 cg.sig(Void.TYPE));
268         mv.visitInsn(Opcodes.RETURN);
269         mv.visitMaxs(1, 1);
270         mv.visitEnd();
271     }
272     
273     public Object JavaDoc beginMethod(String JavaDoc friendlyName, int arity, int localVarCount) {
274         MethodVisitor newMethod = getClassVisitor().visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, friendlyName, METHOD_SIGNATURE, null, null);
275         pushMethodVisitor(newMethod);
276         
277         newMethod.visitCode();
278         
279         // logic to start off the root node's code with local var slots and all
280
newMethod.visitLdcInsn(new Integer JavaDoc(localVarCount));
281         newMethod.visitTypeInsn(Opcodes.ANEWARRAY, cg.p(IRubyObject.class));
282         
283         // store the local vars in a local variable
284
newMethod.visitVarInsn(Opcodes.ASTORE, LOCAL_VARS_INDEX);
285         
286         // put a null at register 4, for closure creation to know we're at top-level or local scope
287
newMethod.visitInsn(Opcodes.ACONST_NULL);
288         newMethod.visitVarInsn(Opcodes.ASTORE, SCOPE_INDEX);
289         
290         // set up a local IRuby variable
291
newMethod.visitVarInsn(Opcodes.ALOAD, THREADCONTEXT_INDEX);
292         invokeThreadContext("getRuntime", cg.sig(Ruby.class));
293         newMethod.visitVarInsn(Opcodes.ASTORE, RUNTIME_INDEX);
294         
295         // visit a label to start scoping for local vars in this method
296
Label start = new Label();
297         newMethod.visitLabel(start);
298         pushScopeStart(start);
299         
300         // push down the argument count of this method
301
pushArity(arity);
302         
303         return newMethod;
304     }
305     
306     public void endMethod(Object JavaDoc token) {
307         assert token instanceof MethodVisitor;
308         
309         MethodVisitor mv = (MethodVisitor)token;
310         // return last value from execution
311
mv.visitInsn(Opcodes.ARETURN);
312         
313         // end of variable scope
314
Label end = new Label();
315         mv.visitLabel(end);
316         
317         // local variable for lvars array
318
mv.visitLocalVariable("lvars", cg.ci(IRubyObject[].class), null, popScopeStart(), end, LOCAL_VARS_INDEX);
319         
320         mv.visitMaxs(1, 1); // automatically calculated by ASM
321
mv.visitEnd();
322         
323         popMethodVisitor();
324         popArity();
325     }
326     
327     public void lineNumber(ISourcePosition position) {
328         if (lastLine == (lastLine = position.getEndLine())) return; // did not change lines for this node, don't bother relabeling
329

330         Label l = new Label();
331         MethodVisitor mv = getMethodVisitor();
332         mv.visitLabel(l);
333         mv.visitLineNumber(position.getEndLine(), l);
334     }
335     
336     public void invokeDynamic(String JavaDoc name, boolean hasReceiver, boolean hasArgs, ClosureCallback closureArg) {
337         MethodVisitor mv = getMethodVisitor();
338         String JavaDoc callType = null;
339         String JavaDoc callSig = cg.sig(IRubyObject.class, cg.params(ThreadContext.class, String JavaDoc.class, IRubyObject[].class, CallType.class, Block.class));
340         String JavaDoc callSigIndexed = cg.sig(IRubyObject.class, cg.params(ThreadContext.class, Byte.TYPE, String JavaDoc.class, IRubyObject[].class, CallType.class, Block.class));
341         
342         byte index = MethodIndex.getIndex(name);
343         
344         if (hasArgs) {
345             if (hasReceiver) {
346                 // Call with args
347
// receiver already present
348

349                 loadThreadContext();
350                 // put under args
351
mv.visitInsn(Opcodes.SWAP);
352                 
353                 callType = "NORMAL";
354             } else {
355                 // FCall
356
// no receiver present, use self
357
loadSelf();
358                 // put self under args
359
mv.visitInsn(Opcodes.SWAP);
360                 
361                 loadThreadContext();
362                 // put under args
363
mv.visitInsn(Opcodes.SWAP);
364                 
365                 callType = "FUNCTIONAL";
366             }
367             
368             if (index != 0) {
369                 // load method index
370
mv.visitLdcInsn(new Byte JavaDoc(index));
371                 // put under args
372
mv.visitInsn(Opcodes.SWAP);
373             }
374             
375             mv.visitLdcInsn(name);
376             // put under args
377
mv.visitInsn(Opcodes.SWAP);
378         } else {
379             if (hasReceiver) {
380                 // Call with no args
381
// receiver already present
382

383                 loadThreadContext();
384                 
385                 callType = "FUNCTIONAL";
386             } else {
387                 // VCall
388
// no receiver present, use self
389
loadSelf();
390                 
391                 loadThreadContext();
392                 
393                 callType = "VARIABLE";
394             }
395             
396             
397             if (index != 0) {
398                 // load method index
399
mv.visitLdcInsn(new Byte JavaDoc(index));
400             }
401             
402             mv.visitLdcInsn(name);
403             
404             // empty args list
405
mv.visitFieldInsn(Opcodes.GETSTATIC, cg.p(IRubyObject.class), "NULL_ARRAY", cg.ci(IRubyObject[].class));
406         }
407         
408         mv.visitFieldInsn(Opcodes.GETSTATIC, cg.p(CallType.class), callType, cg.ci(CallType.class));
409         
410         if (closureArg == null) {
411             mv.visitInsn(Opcodes.ACONST_NULL);
412         } else {
413             closureArg.compile(this);
414         }
415         
416         if (index != 0) {
417             invokeIRubyObject("callMethod", callSigIndexed);
418         } else {
419             invokeIRubyObject("callMethod", callSig);
420         }
421     }
422     
423     public void yield(boolean hasArgs) {
424         loadClosure();
425         
426         MethodVisitor method = getMethodVisitor();
427         
428         method.visitInsn(Opcodes.DUP);
429         loadThreadContext();
430         method.visitInsn(Opcodes.SWAP);
431         
432         invokeThreadContext("raiseErrorIfNoBlock", cg.sig(Void.TYPE, cg.params(Block.class)));
433         
434         if (hasArgs) {
435             method.visitInsn(Opcodes.SWAP);
436             
437             loadThreadContext();
438             method.visitInsn(Opcodes.SWAP);
439             
440             // args now here
441
} else {
442             loadThreadContext();
443             
444             // empty args
445
method.visitInsn(Opcodes.ACONST_NULL);
446         }
447         
448         loadSelf();
449         getRubyClass();
450         method.visitLdcInsn(Boolean.FALSE);
451         
452         method.visitMethodInsn(Opcodes.INVOKEVIRTUAL, cg.p(Block.class), "yield", cg.sig(IRubyObject.class, cg.params(ThreadContext.class, IRubyObject.class, IRubyObject.class, RubyModule.class, Boolean.TYPE)));
453     }
454     
455     private void invokeIRubyObject(String JavaDoc methodName, String JavaDoc signature) {
456         getMethodVisitor().visitMethodInsn(Opcodes.INVOKEINTERFACE, IRUBYOBJECT, methodName, signature);
457     }
458     
459     public void loadThreadContext() {
460         getMethodVisitor().visitVarInsn(Opcodes.ALOAD, THREADCONTEXT_INDEX);
461     }
462     
463     public void loadClosure() {
464         getMethodVisitor().visitVarInsn(Opcodes.ALOAD, CLOSURE_INDEX);
465     }
466     
467     public void loadSelf() {
468         getMethodVisitor().visitVarInsn(Opcodes.ALOAD, SELF_INDEX);
469     }
470     
471     public void loadRuntime() {
472         getMethodVisitor().visitVarInsn(Opcodes.ALOAD, RUNTIME_INDEX);
473     }
474     
475     public void loadNil() {
476         loadRuntime();
477         invokeIRuby("getNil", cg.sig(IRubyObject.class));
478     }
479     
480     public void consumeCurrentValue() {
481         getMethodVisitor().visitInsn(Opcodes.POP);
482     }
483     
484     public void retrieveSelf() {
485         loadSelf();
486     }
487     
488     public void assignLocalVariable(int index) {
489         MethodVisitor mv = getMethodVisitor();
490         mv.visitInsn(Opcodes.DUP);
491         //if ((index - 2) < Math.abs(getArity())) {
492
// load from the incoming params
493
// index is 2-based, and our zero is runtime
494

495             // load args array
496
// mv.visitVarInsn(Opcodes.ALOAD, ARGS_INDEX);
497
// index = index - 2;
498
//} else {
499
mv.visitVarInsn(Opcodes.ALOAD, LOCAL_VARS_INDEX);
500         //}
501

502         mv.visitInsn(Opcodes.SWAP);
503         mv.visitLdcInsn(new Integer JavaDoc(index));
504         mv.visitInsn(Opcodes.SWAP);
505         mv.visitInsn(Opcodes.AASTORE);
506     }
507     
508     public void retrieveLocalVariable(int index) {
509         MethodVisitor mv = getMethodVisitor();
510         
511         
512         // check if it's an argument
513
//if ((index - 2) < Math.abs(getArity())) {
514
// load from the incoming params
515
// index is 2-based, and our zero is runtime
516

517             // load args array
518
// mv.visitVarInsn(Opcodes.ALOAD, ARGS_INDEX);
519
// mv.visitLdcInsn(new Integer(index - 2));
520
// mv.visitInsn(Opcodes.AALOAD);
521
//} else {
522
mv.visitVarInsn(Opcodes.ALOAD, LOCAL_VARS_INDEX);
523             mv.visitLdcInsn(new Integer JavaDoc(index));
524             mv.visitInsn(Opcodes.AALOAD);
525         //}
526
}
527     
528     public void assignLocalVariable(int index, int depth) {
529         if (depth == 0) {
530             assignLocalVariable(index);
531             return;
532         }
533
534         MethodVisitor mv = getMethodVisitor();
535         mv.visitInsn(Opcodes.DUP);
536         
537         // get the appropriate array out of the scopes
538
mv.visitVarInsn(Opcodes.ALOAD, SCOPE_INDEX);
539         mv.visitLdcInsn(new Integer JavaDoc(depth - 1));
540         mv.visitInsn(Opcodes.AALOAD);
541         
542         // insert the value into the array at the specified index
543
mv.visitInsn(Opcodes.SWAP);
544         mv.visitLdcInsn(new Integer JavaDoc(index));
545         mv.visitInsn(Opcodes.SWAP);
546         mv.visitInsn(Opcodes.AASTORE);
547     }
548     
549     public void retrieveLocalVariable(int index, int depth) {
550         if (depth == 0) {
551             retrieveLocalVariable(index);
552             return;
553         }
554         
555         MethodVisitor mv = getMethodVisitor();
556         
557         // get the appropriate array out of the scopes
558
mv.visitVarInsn(Opcodes.ALOAD, SCOPE_INDEX);
559         mv.visitLdcInsn(new Integer JavaDoc(depth - 1));
560         mv.visitInsn(Opcodes.AALOAD);
561         
562         // load the value from the array at the specified index
563
mv.visitLdcInsn(new Integer JavaDoc(index));
564         mv.visitInsn(Opcodes.AALOAD);
565     }
566     
567     public void retrieveConstant(String JavaDoc name) {
568         MethodVisitor mv = getMethodVisitor();
569         
570         // FIXME this doesn't work right yet since TC.getConstant depends on TC state
571
loadThreadContext();
572         mv.visitLdcInsn(name);
573         invokeThreadContext("getConstant", cg.sig(IRubyObject.class, cg.params(String JavaDoc.class)));
574     }
575     
576     public void createNewFixnum(long value) {
577         MethodVisitor mv = getMethodVisitor();
578         
579         loadRuntime();
580         mv.visitLdcInsn(new Long JavaDoc(value));
581         
582         invokeIRuby("newFixnum", cg.sig(RubyFixnum.class, cg.params(Long.TYPE)));
583     }
584     
585     public void createNewBignum(java.math.BigInteger JavaDoc value) {
586         MethodVisitor mv = getMethodVisitor();
587         
588         loadRuntime();
589         mv.visitLdcInsn(value.toString());
590         
591         mv.visitMethodInsn(Opcodes.INVOKESTATIC,cg.p(org.jruby.RubyBignum.class) , "newBignum", cg.sig(org.jruby.RubyBignum.class,cg.params(Ruby.class,String JavaDoc.class)));
592     }
593     
594     public void createNewString(ByteList value) {
595         MethodVisitor mv = getMethodVisitor();
596         
597         loadRuntime();
598         mv.visitLdcInsn(value.toString());
599         
600         invokeIRuby("newString", cg.sig(RubyString.class, cg.params(String JavaDoc.class)));
601     }
602     
603     public void createNewSymbol(String JavaDoc name) {
604         loadRuntime();
605         getMethodVisitor().visitLdcInsn(name);
606         invokeIRuby("newSymbol", cg.sig(RubySymbol.class, cg.params(String JavaDoc.class)));
607     }
608     
609     public void createNewArray() {
610         MethodVisitor mv = getMethodVisitor();
611         
612         loadRuntime();
613         // put under object array already present
614
mv.visitInsn(Opcodes.SWAP);
615         
616         invokeIRuby("newArray", cg.sig(RubyArray.class, cg.params(IRubyObject[].class)));
617     }
618     
619     public void createEmptyArray() {
620         MethodVisitor mv = getMethodVisitor();
621         
622         loadRuntime();
623         
624         invokeIRuby("newArray", cg.sig(RubyArray.class, cg.params()));
625     }
626     
627     public void createObjectArray(Object JavaDoc[] sourceArray, ArrayCallback callback) {
628         buildObjectArray(IRUBYOBJECT, sourceArray, callback);
629     }
630     
631     private void buildObjectArray(String JavaDoc type, Object JavaDoc[] sourceArray, ArrayCallback callback) {
632         MethodVisitor mv = getMethodVisitor();
633         
634         mv.visitLdcInsn(new Integer JavaDoc(sourceArray.length));
635         mv.visitTypeInsn(Opcodes.ANEWARRAY, type);
636         
637         for (int i = 0; i < sourceArray.length; i++) {
638             mv.visitInsn(Opcodes.DUP);
639             mv.visitLdcInsn(new Integer JavaDoc(i));
640             
641             callback.nextValue(this, sourceArray, i);
642             
643             mv.visitInsn(Opcodes.AASTORE);
644         }
645     }
646     /**
647      * Invoke IRubyObject.isTrue
648      */

649     private void isTrue() {
650         invokeIRubyObject("isTrue", cg.sig(Boolean.TYPE));
651     }
652     
653     public void performBooleanBranch(BranchCallback trueBranch, BranchCallback falseBranch) {
654         Label afterJmp = new Label();
655         Label falseJmp = new Label();
656         
657         MethodVisitor mv = getMethodVisitor();
658         
659         // call isTrue on the result
660
isTrue();
661         
662         mv.visitJumpInsn(Opcodes.IFEQ, falseJmp); // EQ == 0 (i.e. false)
663
trueBranch.branch(this);
664         mv.visitJumpInsn(Opcodes.GOTO, afterJmp);
665         
666         // FIXME: optimize for cases where we have no false branch
667
mv.visitLabel(falseJmp);
668         falseBranch.branch(this);
669         
670         mv.visitLabel(afterJmp);
671     }
672     
673     public void performLogicalAnd(BranchCallback longBranch) {
674         Label afterJmp = new Label();
675         Label falseJmp = new Label();
676         
677         MethodVisitor mv = getMethodVisitor();
678         
679         // dup it since we need to return appropriately if it's false
680
mv.visitInsn(Opcodes.DUP);
681         
682         // call isTrue on the result
683
isTrue();
684         
685         mv.visitJumpInsn(Opcodes.IFEQ, falseJmp); // EQ == 0 (i.e. false)
686
// pop the extra result and replace with the send part of the AND
687
mv.visitInsn(Opcodes.POP);
688         longBranch.branch(this);
689         mv.visitLabel(falseJmp);
690     }
691     
692     public void performLogicalOr(BranchCallback longBranch) {
693         Label afterJmp = new Label();
694         Label falseJmp = new Label();
695         
696         MethodVisitor mv = getMethodVisitor();
697         
698         // dup it since we need to return appropriately if it's false
699
mv.visitInsn(Opcodes.DUP);
700         
701         // call isTrue on the result
702
isTrue();
703         
704         mv.visitJumpInsn(Opcodes.IFNE, falseJmp); // EQ == 0 (i.e. false)
705
// pop the extra result and replace with the send part of the AND
706
mv.visitInsn(Opcodes.POP);
707         longBranch.branch(this);
708         mv.visitLabel(falseJmp);
709     }
710     
711     public void performBooleanLoop(BranchCallback condition, BranchCallback body, boolean checkFirst) {
712         // FIXME: handle next/continue, break, etc
713
MethodVisitor mv = getMethodVisitor();
714         
715         Label endJmp = new Label();
716         if (checkFirst) {
717             // calculate condition
718
condition.branch(this);
719             // call isTrue on the result
720
isTrue();
721             
722             mv.visitJumpInsn(Opcodes.IFEQ, endJmp); // EQ == 0 (i.e. false)
723
}
724         
725         Label topJmp = new Label();
726         
727         mv.visitLabel(topJmp);
728         
729         body.branch(this);
730         
731         // clear result after each loop
732
mv.visitInsn(Opcodes.POP);
733         
734         // calculate condition
735
condition.branch(this);
736         // call isTrue on the result
737
isTrue();
738         
739         mv.visitJumpInsn(Opcodes.IFNE, topJmp); // NE == nonzero (i.e. true)
740

741         if (checkFirst) {
742             mv.visitLabel(endJmp);
743         }
744         
745         loadNil();
746     }
747     
748     public static CompiledBlock createBlock(ThreadContext context, IRubyObject self, int arity, IRubyObject[][] scopes, CompiledBlockCallback callback) {
749         return new CompiledBlock(context, self, Arity.createArity(arity), scopes, callback);
750     }
751     
752     public void createNewClosure(StaticScope scope, int arity, ClosureCallback body) {
753         // FIXME: This isn't quite done yet; waiting to have full support for passing closures so we can test it
754
ClassVisitor cv = getClassVisitor();
755         MethodVisitor method;
756         
757         String JavaDoc closureMethodName = "closure" + ++innerIndex;
758         String JavaDoc closureFieldName = "_" + closureMethodName;
759         
760         // declare the field
761
cv.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC, closureFieldName, cg.ci(CompiledBlockCallback.class), null, null);
762         
763         ////////////////////////////
764
// closure implementation
765
method = cv.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, closureMethodName, CLOSURE_SIGNATURE, null, null);
766         pushMethodVisitor(method);
767         
768         method.visitCode();
769         
770         // logic to start off the closure with dvar slots
771
method.visitLdcInsn(new Integer JavaDoc(scope.getNumberOfVariables()));
772         method.visitTypeInsn(Opcodes.ANEWARRAY, cg.p(IRubyObject.class));
773         
774         // store the dvars in a local variable
775
method.visitVarInsn(Opcodes.ASTORE, LOCAL_VARS_INDEX);
776         
777         // arraycopy arguments into local vars array
778
if (arity != 0) {
779             // array index OOB for some reason; perhaps because we're not actually handling args right?
780
/*method.visitVarInsn(Opcodes.ALOAD, ARGS_INDEX);
781             method.visitInsn(Opcodes.ICONST_0);
782             method.visitVarInsn(Opcodes.ALOAD, LOCAL_VARS_INDEX);
783             mv.visitInsn(Opcodes.ICONST_2);
784             method.visitLdcInsn(new Integer(arity));
785             method.visitMethodInsn(Opcodes.INVOKESTATIC, cg.p(System.class), "arraycopy", cg.sig(Void.TYPE, cg.params(Object.class, Integer.TYPE, Object.class, Integer.TYPE, Integer.TYPE)));*/

786         }
787         
788         // Containing scopes are passed as IRubyObject[][] in the SCOPE_INDEX var
789

790         // set up a local IRuby variable
791
method.visitVarInsn(Opcodes.ALOAD, THREADCONTEXT_INDEX);
792         invokeThreadContext("getRuntime", cg.sig(Ruby.class));
793         method.visitVarInsn(Opcodes.ASTORE, RUNTIME_INDEX);
794         
795         // start of scoping for closure's vars
796
Label start = new Label();
797         method.visitLabel(start);
798         
799         // visit the body of the closure
800
body.compile(this);
801         
802         method.visitInsn(Opcodes.ARETURN);
803         
804         // end of scoping for closure's vars
805
Label end = new Label();
806         method.visitLabel(end);
807         method.visitMaxs(1, 1);
808         method.visitEnd();
809         
810         popMethodVisitor();
811         
812         method = getMethodVisitor();
813         
814         // Now, store a compiled block object somewhere we can access it in the future
815

816         // in current method, load the field to see if we've created a BlockCallback yet
817
method.visitFieldInsn(Opcodes.GETSTATIC, classname, closureFieldName, cg.ci(CompiledBlockCallback.class));
818         Label alreadyCreated = new Label();
819         method.visitJumpInsn(Opcodes.IFNONNULL, alreadyCreated);
820         
821         // no callback, construct it
822
getCallbackFactory();
823         
824         method.visitLdcInsn(closureMethodName);
825         method.visitMethodInsn(Opcodes.INVOKEVIRTUAL, cg.p(CallbackFactory.class), "getBlockCallback", cg.sig(CompiledBlockCallback.class, cg.params(String JavaDoc.class)));
826         method.visitFieldInsn(Opcodes.PUTSTATIC, classname, closureFieldName, cg.ci(CompiledBlockCallback.class));
827         
828         method.visitLabel(alreadyCreated);
829         
830         // Construct the block for passing to the target method
831
loadThreadContext();
832         loadSelf();
833         method.visitLdcInsn(new Integer JavaDoc(arity));
834         
835         // create an array of scopes to use
836

837         // check if we have containing scopes
838
method.visitVarInsn(Opcodes.ALOAD, SCOPE_INDEX);
839         Label noScopes = new Label();
840         Label copyLocals = new Label();
841         method.visitJumpInsn(Opcodes.IFNULL, noScopes);
842         
843         // we have containing scopes, include them
844

845         // get length of current scopes array, add one
846
method.visitVarInsn(Opcodes.ALOAD, SCOPE_INDEX);
847         method.visitInsn(Opcodes.ARRAYLENGTH);
848         method.visitInsn(Opcodes.ICONST_1);
849         method.visitInsn(Opcodes.IADD);
850         
851         // create new scopes array
852
method.visitTypeInsn(Opcodes.ANEWARRAY, cg.p(IRubyObject[].class));
853         
854         // copy containing scopes to index one and on
855
method.visitInsn(Opcodes.DUP);
856         method.visitVarInsn(Opcodes.ALOAD, SCOPE_INDEX);
857         method.visitInsn(Opcodes.SWAP);
858         method.visitInsn(Opcodes.ICONST_0);
859         method.visitInsn(Opcodes.SWAP);
860         // new scopes array is here now
861
method.visitInsn(Opcodes.ICONST_1);
862         method.visitVarInsn(Opcodes.ALOAD, SCOPE_INDEX);
863         method.visitInsn(Opcodes.ARRAYLENGTH);
864         method.visitMethodInsn(Opcodes.INVOKESTATIC, cg.p(System JavaDoc.class), "arraycopy", cg.sig(Void.TYPE, cg.params(Object JavaDoc.class, Integer.TYPE, Object JavaDoc.class, Integer.TYPE, Integer.TYPE)));
865
866         method.visitJumpInsn(Opcodes.GOTO, copyLocals);
867         
868         method.visitLabel(noScopes);
869
870         // create new scopes array
871
method.visitInsn(Opcodes.ICONST_1);
872         method.visitTypeInsn(Opcodes.ANEWARRAY, cg.p(IRubyObject[].class));
873         
874         method.visitLabel(copyLocals);
875
876         // store local vars at index zero
877
method.visitInsn(Opcodes.DUP);
878         method.visitInsn(Opcodes.ICONST_0);
879         method.visitVarInsn(Opcodes.ALOAD, LOCAL_VARS_INDEX);
880         method.visitInsn(Opcodes.AASTORE);
881         
882         method.visitFieldInsn(Opcodes.GETSTATIC, classname, closureFieldName, cg.ci(CompiledBlockCallback.class));
883         
884         method.visitMethodInsn(Opcodes.INVOKESTATIC, cg.p(StandardASMCompiler.class), "createBlock",
885                 cg.sig(CompiledBlock.class, cg.params(ThreadContext.class, IRubyObject.class, Integer.TYPE, IRubyObject[][].class, CompiledBlockCallback.class)));
886     }
887     
888     private void invokeThreadContext(String JavaDoc methodName, String JavaDoc signature) {
889         MethodVisitor mv = getMethodVisitor();
890         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, THREADCONTEXT, methodName, signature);
891     }
892     
893     private void invokeIRuby(String JavaDoc methodName, String JavaDoc signature) {
894         MethodVisitor mv = getMethodVisitor();
895         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, RUBY, methodName, signature);
896     }
897     
898     private void getCallbackFactory() {
899         loadRuntime();
900         MethodVisitor mv = getMethodVisitor();
901         mv.visitLdcInsn(classname);
902         mv.visitMethodInsn(Opcodes.INVOKESTATIC, cg.p(Class JavaDoc.class), "forName", cg.sig(Class JavaDoc.class, cg.params(String JavaDoc.class)));
903         invokeIRuby("callbackFactory", cg.sig(CallbackFactory.class, cg.params(Class JavaDoc.class)));
904     }
905     
906     private void getRubyClass() {
907         loadSelf();
908         // FIXME: This doesn't seem *quite* right. If actually within a class...end, is self.getMetaClass the correct class? should be self, no?
909
invokeIRubyObject("getMetaClass", cg.sig(RubyClass.class));
910     }
911     
912     private void getCRef() {
913         loadThreadContext();
914         // FIXME: This doesn't seem *quite* right. If actually within a class...end, is self.getMetaClass the correct class? should be self, no?
915
invokeThreadContext("peekCRef", cg.sig(SinglyLinkedList.class));
916     }
917     
918     private void newTypeError(String JavaDoc error) {
919         loadRuntime();
920         getMethodVisitor().visitLdcInsn(error);
921         invokeIRuby("newTypeError", cg.sig(RaiseException.class, cg.params(String JavaDoc.class)));
922     }
923     
924     private void getCurrentVisibility() {
925         loadThreadContext();
926         invokeThreadContext("getCurrentVisibility", cg.sig(Visibility.class));
927     }
928     
929     private void println() {
930         MethodVisitor mv = getMethodVisitor();
931         
932         mv.visitInsn(Opcodes.DUP);
933         mv.visitFieldInsn(Opcodes.GETSTATIC, cg.p(System JavaDoc.class), "out", cg.ci(PrintStream JavaDoc.class));
934         mv.visitInsn(Opcodes.SWAP);
935         
936         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, cg.p(PrintStream JavaDoc.class), "println", cg.sig(Void.TYPE, cg.params(Object JavaDoc.class)));
937     }
938     
939     public void defineAlias(String JavaDoc newName, String JavaDoc oldName) {
940         getRubyClass();
941         getMethodVisitor().visitLdcInsn(newName);
942         getMethodVisitor().visitLdcInsn(oldName);
943         getMethodVisitor().visitMethodInsn(Opcodes.INVOKEVIRTUAL, cg.p(RubyModule.class), "defineAlias", cg.sig(Void.TYPE,cg.params(String JavaDoc.class,String JavaDoc.class)));
944         loadNil();
945         // TODO: should call method_added, and possibly push nil.
946
}
947     
948     public static IRubyObject def(ThreadContext context, IRubyObject self, Class JavaDoc compiledClass, String JavaDoc name, String JavaDoc javaName, int arity) {
949         Ruby runtime = context.getRuntime();
950         
951         // FIXME: This is what the old def did, but doesn't work in the compiler for top-level methods. Hmm.
952
//RubyModule containingClass = context.getRubyClass();
953
RubyModule containingClass = self.getMetaClass();
954         
955         if (containingClass == null) {
956             throw runtime.newTypeError("No class to add method.");
957         }
958         
959         if (containingClass == runtime.getObject() && name == "initialize") {
960             runtime.getWarnings().warn("redefining Object#initialize may cause infinite loop");
961         }
962         
963         Visibility visibility = context.getCurrentVisibility();
964         if (name == "initialize" || visibility.isModuleFunction() || context.isTopLevel()) {
965             visibility = Visibility.PRIVATE;
966         }
967         
968         SinglyLinkedList cref = context.peekCRef();
969         
970         MethodFactory factory = MethodFactory.createFactory();
971         DynamicMethod method = factory.getCompiledMethod(containingClass, compiledClass, javaName, Arity.createArity(arity), visibility, cref);
972         
973         containingClass.addMethod(name, method);
974         
975         if (context.getCurrentVisibility().isModuleFunction()) {
976             containingClass.getSingletonClass().addMethod(
977                     name,
978                     new WrapperMethod(containingClass.getSingletonClass(), method,
979                     Visibility.PUBLIC));
980             containingClass.callMethod(context, "singleton_method_added", runtime.newSymbol(name));
981         }
982         
983         // 'class << state.self' and 'class << obj' uses defn as opposed to defs
984
if (containingClass.isSingleton()) {
985             ((MetaClass) containingClass).getAttachedObject().callMethod(
986                     context, "singleton_method_added", runtime.newSymbol(name));
987         } else {
988             containingClass.callMethod(context, "method_added", runtime.newSymbol(name));
989         }
990         
991         return runtime.getNil();
992     }
993     
994     public void defineNewMethod(String JavaDoc name, int arity, int localVarCount, ClosureCallback body) {
995         // TODO: build arg list based on number of args, optionals, etc
996
++methodIndex;
997         String JavaDoc methodName = name + "__" + methodIndex;
998         beginMethod(methodName, arity, localVarCount);
999         
1000        MethodVisitor mv = getMethodVisitor();
1001        
1002        mv.visitCode();
1003        
1004        // arraycopy arguments into local vars array
1005
mv.visitVarInsn(Opcodes.ALOAD, ARGS_INDEX);
1006        mv.visitInsn(Opcodes.ICONST_0);
1007        mv.visitVarInsn(Opcodes.ALOAD, LOCAL_VARS_INDEX);
1008        mv.visitInsn(Opcodes.ICONST_2);
1009        mv.visitLdcInsn(new Integer JavaDoc(arity));
1010        mv.visitMethodInsn(Opcodes.INVOKESTATIC, cg.p(System JavaDoc.class), "arraycopy", cg.sig(Void.TYPE, cg.params(Object JavaDoc.class, Integer.TYPE, Object JavaDoc.class, Integer.TYPE, Integer.TYPE)));
1011        
1012        // put a null at register 4, for closure creation to know we're at top-level or local scope
1013
mv.visitInsn(Opcodes.ACONST_NULL);
1014        mv.visitVarInsn(Opcodes.ASTORE, SCOPE_INDEX);
1015        
1016        // callback to fill in method body
1017
body.compile(this);
1018        
1019        endMethod(mv);
1020        
1021        // return to previous method
1022
mv = getMethodVisitor();
1023        
1024        // prepare to call "def" utility method to handle def logic
1025
loadThreadContext();
1026        
1027        loadSelf();
1028        
1029        mv.visitLdcInsn(classname.replace('/', '.'));
1030        mv.visitMethodInsn(Opcodes.INVOKESTATIC, cg.p(Class JavaDoc.class), "forName", cg.sig(Class JavaDoc.class, cg.params(String JavaDoc.class)));
1031        
1032        mv.visitLdcInsn(name);
1033        
1034        mv.visitLdcInsn(methodName);
1035        
1036        mv.visitLdcInsn(new Integer JavaDoc(arity));
1037        
1038        mv.visitMethodInsn(Opcodes.INVOKESTATIC,
1039                cg.p(StandardASMCompiler.class),
1040                "def",
1041                cg.sig(IRubyObject.class, cg.params(ThreadContext.class, IRubyObject.class, Class JavaDoc.class, String JavaDoc.class, String JavaDoc.class, Integer.TYPE)));
1042    }
1043    
1044    public void loadFalse() {
1045        loadRuntime();
1046        invokeIRuby("getFalse", cg.sig(RubyBoolean.class));
1047    }
1048    
1049    public void loadTrue() {
1050        loadRuntime();
1051        invokeIRuby("getTrue", cg.sig(RubyBoolean.class));
1052    }
1053    
1054    public void retrieveInstanceVariable(String JavaDoc name) {
1055        loadSelf();
1056        
1057        MethodVisitor mv = getMethodVisitor();
1058        
1059        mv.visitLdcInsn(name);
1060        invokeIRubyObject("getInstanceVariable", cg.sig(IRubyObject.class, cg.params(String JavaDoc.class)));
1061        
1062        // check if it's null; if so, load nil
1063
mv.visitInsn(Opcodes.DUP);
1064        Label notNull = new Label();
1065        mv.visitJumpInsn(Opcodes.IFNONNULL, notNull);
1066        
1067        // pop the dup'ed null
1068
mv.visitInsn(Opcodes.POP);
1069        // replace it with nil
1070
loadNil();
1071        
1072        mv.visitLabel(notNull);
1073    }
1074    
1075    public void assignInstanceVariable(String JavaDoc name) {
1076        MethodVisitor mv = getMethodVisitor();
1077        
1078        loadSelf();
1079        mv.visitInsn(Opcodes.SWAP);
1080        
1081        mv.visitLdcInsn(name);
1082        mv.visitInsn(Opcodes.SWAP);
1083        
1084        invokeIRubyObject("setInstanceVariable", cg.sig(IRubyObject.class, cg.params(String JavaDoc.class, IRubyObject.class)));
1085    }
1086    
1087    public void retrieveGlobalVariable(String JavaDoc name) {
1088        loadRuntime();
1089        
1090        MethodVisitor mv = getMethodVisitor();
1091        
1092        invokeIRuby("getGlobalVariables", cg.sig(GlobalVariables.class));
1093        mv.visitLdcInsn(name);
1094        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, cg.p(GlobalVariables.class), "get", cg.sig(IRubyObject.class, cg.params(String JavaDoc.class)));
1095    }
1096    
1097    public void assignGlobalVariable(String JavaDoc name) {
1098        loadRuntime();
1099        
1100        MethodVisitor mv = getMethodVisitor();
1101        
1102        invokeIRuby("getGlobalVariables", cg.sig(GlobalVariables.class));
1103        mv.visitInsn(Opcodes.SWAP);
1104        mv.visitLdcInsn(name);
1105        mv.visitInsn(Opcodes.SWAP);
1106        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, cg.p(GlobalVariables.class), "set", cg.sig(IRubyObject.class, cg.params(String JavaDoc.class, IRubyObject.class)));
1107    }
1108    
1109    public void negateCurrentValue() {
1110        MethodVisitor mv = getMethodVisitor();
1111        
1112        isTrue();
1113        Label isTrue = new Label();
1114        Label end = new Label();
1115        mv.visitJumpInsn(Opcodes.IFNE, isTrue);
1116        loadTrue();
1117        mv.visitJumpInsn(Opcodes.GOTO, end);
1118        mv.visitLabel(isTrue);
1119        loadFalse();
1120        mv.visitLabel(end);
1121    }
1122    
1123    public void splatCurrentValue() {
1124        MethodVisitor method = getMethodVisitor();
1125        
1126        method.visitMethodInsn(Opcodes.INVOKESTATIC, cg.p(EvaluationState.class), "splatValue", cg.sig(IRubyObject.class, cg.params(IRubyObject.class)));
1127    }
1128    
1129    public void singlifySplattedValue() {
1130        MethodVisitor method = getMethodVisitor();
1131        method.visitMethodInsn(Opcodes.INVOKESTATIC, cg.p(EvaluationState.class), "aValueSplat", cg.sig(IRubyObject.class, cg.params(IRubyObject.class)));
1132    }
1133    
1134    public void ensureRubyArray() {
1135        MethodVisitor method = getMethodVisitor();
1136        
1137        method.visitMethodInsn(Opcodes.INVOKESTATIC, cg.p(StandardASMCompiler.class), "ensureRubyArray", cg.sig(RubyArray.class, cg.params(IRubyObject.class)));
1138    }
1139    
1140    public static RubyArray ensureRubyArray(IRubyObject value) {
1141        if (!(value instanceof RubyArray)) {
1142            value = RubyArray.newArray(value.getRuntime(), value);
1143        }
1144        return (RubyArray)value;
1145    }
1146    
1147    public void forEachInValueArray(int start, int count, Object JavaDoc source, ArrayCallback callback) {
1148        MethodVisitor method = getMethodVisitor();
1149        
1150        Label noMoreArrayElements = new Label();
1151        for (; start < count; start++) {
1152            // confirm we're not past the end of the array
1153
method.visitInsn(Opcodes.DUP); // dup the original array object
1154
method.visitMethodInsn(Opcodes.INVOKEVIRTUAL, cg.p(RubyArray.class), "getLength", cg.sig(Integer.TYPE, cg.params()));
1155            method.visitLdcInsn(new Integer JavaDoc(start));
1156            method.visitJumpInsn(Opcodes.IFLE, noMoreArrayElements); // if length <= start, end loop
1157

1158            // extract item from array
1159
method.visitInsn(Opcodes.DUP); // dup the original array object
1160
method.visitLdcInsn(new Integer JavaDoc(start)); // index for the item
1161
method.visitMethodInsn(Opcodes.INVOKEVIRTUAL, cg.p(RubyArray.class), "entry",
1162                    cg.sig(IRubyObject.class, cg.params(Long.TYPE))); // extract item
1163
callback.nextValue(this, source, start);
1164        }
1165        method.visitLabel(noMoreArrayElements);
1166    }
1167
1168    public void loadInteger(int value) {
1169        throw new UnsupportedOperationException JavaDoc("Not supported yet.");
1170    }
1171
1172    public void performGEBranch(BranchCallback trueBranch,
1173                                BranchCallback falseBranch) {
1174        throw new UnsupportedOperationException JavaDoc("Not supported yet.");
1175    }
1176
1177    public void performGTBranch(BranchCallback trueBranch,
1178                                BranchCallback falseBranch) {
1179        throw new UnsupportedOperationException JavaDoc("Not supported yet.");
1180    }
1181
1182    public void performLEBranch(BranchCallback trueBranch,
1183                                BranchCallback falseBranch) {
1184        throw new UnsupportedOperationException JavaDoc("Not supported yet.");
1185    }
1186
1187    public void performLTBranch(BranchCallback trueBranch,
1188                                BranchCallback falseBranch) {
1189        throw new UnsupportedOperationException JavaDoc("Not supported yet.");
1190    }
1191
1192    public void loadRubyArraySize() {
1193        throw new UnsupportedOperationException JavaDoc("Not supported yet.");
1194    }
1195}
1196
Popular Tags