KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jruby > compiler > InstructionCompiler2


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) 2004-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 package org.jruby.compiler;
29
30 import java.util.HashMap JavaDoc;
31 import java.util.Iterator JavaDoc;
32 import java.util.Map JavaDoc;
33
34 import org.jruby.Ruby;
35 import org.jruby.ast.AliasNode;
36 import org.jruby.ast.AndNode;
37 import org.jruby.ast.ArgsCatNode;
38 import org.jruby.ast.ArgsNode;
39 import org.jruby.ast.ArgsPushNode;
40 import org.jruby.ast.ArrayNode;
41 import org.jruby.ast.AttrAssignNode;
42 import org.jruby.ast.BackRefNode;
43 import org.jruby.ast.BeginNode;
44 import org.jruby.ast.BignumNode;
45 import org.jruby.ast.BlockArgNode;
46 import org.jruby.ast.BlockNode;
47 import org.jruby.ast.BlockPassNode;
48 import org.jruby.ast.BreakNode;
49 import org.jruby.ast.CallNode;
50 import org.jruby.ast.CaseNode;
51 import org.jruby.ast.ClassNode;
52 import org.jruby.ast.ClassVarAsgnNode;
53 import org.jruby.ast.ClassVarDeclNode;
54 import org.jruby.ast.ClassVarNode;
55 import org.jruby.ast.Colon2Node;
56 import org.jruby.ast.Colon3Node;
57 import org.jruby.ast.ConstDeclNode;
58 import org.jruby.ast.ConstNode;
59 import org.jruby.ast.DAsgnNode;
60 import org.jruby.ast.DRegexpNode;
61 import org.jruby.ast.DStrNode;
62 import org.jruby.ast.DSymbolNode;
63 import org.jruby.ast.DVarNode;
64 import org.jruby.ast.DXStrNode;
65 import org.jruby.ast.DefinedNode;
66 import org.jruby.ast.DefnNode;
67 import org.jruby.ast.DefsNode;
68 import org.jruby.ast.DotNode;
69 import org.jruby.ast.EnsureNode;
70 import org.jruby.ast.EvStrNode;
71 import org.jruby.ast.FCallNode;
72 import org.jruby.ast.FalseNode;
73 import org.jruby.ast.FixnumNode;
74 import org.jruby.ast.FlipNode;
75 import org.jruby.ast.FloatNode;
76 import org.jruby.ast.ForNode;
77 import org.jruby.ast.GlobalAsgnNode;
78 import org.jruby.ast.GlobalVarNode;
79 import org.jruby.ast.HashNode;
80 import org.jruby.ast.IfNode;
81 import org.jruby.ast.InstAsgnNode;
82 import org.jruby.ast.InstVarNode;
83 import org.jruby.ast.IterNode;
84 import org.jruby.ast.LocalAsgnNode;
85 import org.jruby.ast.LocalVarNode;
86 import org.jruby.ast.Match2Node;
87 import org.jruby.ast.Match3Node;
88 import org.jruby.ast.MatchNode;
89 import org.jruby.ast.ModuleNode;
90 import org.jruby.ast.MultipleAsgnNode;
91 import org.jruby.ast.NewlineNode;
92 import org.jruby.ast.NextNode;
93 import org.jruby.ast.NilNode;
94 import org.jruby.ast.Node;
95 import org.jruby.ast.NotNode;
96 import org.jruby.ast.NthRefNode;
97 import org.jruby.ast.OpAsgnAndNode;
98 import org.jruby.ast.OpAsgnNode;
99 import org.jruby.ast.OpAsgnOrNode;
100 import org.jruby.ast.OpElementAsgnNode;
101 import org.jruby.ast.OptNNode;
102 import org.jruby.ast.OrNode;
103 import org.jruby.ast.PostExeNode;
104 import org.jruby.ast.RedoNode;
105 import org.jruby.ast.RegexpNode;
106 import org.jruby.ast.RescueBodyNode;
107 import org.jruby.ast.RescueNode;
108 import org.jruby.ast.RetryNode;
109 import org.jruby.ast.ReturnNode;
110 import org.jruby.ast.RootNode;
111 import org.jruby.ast.SClassNode;
112 import org.jruby.ast.SValueNode;
113 import org.jruby.ast.SelfNode;
114 import org.jruby.ast.SplatNode;
115 import org.jruby.ast.StrNode;
116 import org.jruby.ast.SuperNode;
117 import org.jruby.ast.SymbolNode;
118 import org.jruby.ast.ToAryNode;
119 import org.jruby.ast.TrueNode;
120 import org.jruby.ast.UndefNode;
121 import org.jruby.ast.UntilNode;
122 import org.jruby.ast.VAliasNode;
123 import org.jruby.ast.VCallNode;
124 import org.jruby.ast.WhenNode;
125 import org.jruby.ast.WhileNode;
126 import org.jruby.ast.XStrNode;
127 import org.jruby.ast.YieldNode;
128 import org.jruby.ast.ZArrayNode;
129 import org.jruby.ast.ZSuperNode;
130 import org.jruby.ast.visitor.NodeVisitor;
131 import org.jruby.evaluator.Instruction;
132 import org.jruby.internal.runtime.methods.MultiStub;
133 import org.jruby.internal.runtime.methods.MultiStubMethod;
134 import org.jruby.runtime.Arity;
135 import org.jruby.runtime.Visibility;
136 import org.jruby.util.JRubyClassLoader;
137 import org.objectweb.asm.ClassWriter;
138 import org.objectweb.asm.Label;
139 import org.objectweb.asm.MethodVisitor;
140 import org.objectweb.asm.Opcodes;
141 import org.objectweb.asm.Type;
142
143 public class InstructionCompiler2 implements NodeVisitor {
144     private static final String JavaDoc RUBYMODULE = "org/jruby/RubyModule";
145
146     private static final String JavaDoc RUBY = "org/jruby/Ruby";
147
148     private static final String JavaDoc IRUBYOBJECT = "org/jruby/runtime/builtin/IRubyObject";
149
150     //private static final String FRAME = "org/jruby/runtime/Frame";
151

152     private static final String JavaDoc THREADCONTEXT = "org/jruby/runtime/ThreadContext";
153
154     private static final boolean EXPERIMENTAL_SOURCING = true;
155     
156     private ArgsNode args;
157     private ClassWriter cv;
158     private MethodVisitor mv;
159     
160     private int lastLine = 0;
161
162     private boolean runtimeLoaded;
163     
164     Map JavaDoc classWriters = new HashMap JavaDoc();
165     ClassWriter currentMultiStub = null;
166     int multiStubIndex = -1;
167     int multiStubCount = -1;
168
169     private String JavaDoc classname;
170
171     private String JavaDoc sourceName;
172
173     public InstructionCompiler2() {
174     }
175     
176     public void closeOutMultiStub() {
177         if (currentMultiStub != null) {
178             while (multiStubIndex < 9) {
179                 MethodVisitor multiStubMethod = createNewMethod();
180                 multiStubMethod.visitCode();
181                 multiStubMethod.visitInsn(Opcodes.ACONST_NULL);
182                 multiStubMethod.visitInsn(Opcodes.ARETURN);
183                 multiStubMethod.visitMaxs(1, 1);
184                 multiStubMethod.visitEnd();
185             }
186         }
187     }
188     
189     public void defineModuleFunction(Ruby runtime, String JavaDoc module, String JavaDoc name, MultiStub stub, int index, Arity arity, Visibility visibility) {
190         runtime.getModule(module).addMethod(name, new MultiStubMethod(stub, index, runtime.getModule(module), arity, visibility));
191     }
192     
193     public String JavaDoc[] compile(String JavaDoc classname, String JavaDoc sourceName, Node node) {
194         cv = new ClassWriter(true);
195         if (classname.startsWith("-e")) {
196             classname = classname.replaceAll("-e", "DashE");
197         }
198         classWriters.put(classname, cv);
199         this.classname = classname;
200         this.sourceName = sourceName;
201
202         cv.visit(Opcodes.V1_2, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER,
203                 classname, null, "java/lang/Object", new String JavaDoc[] {"org/jruby/ast/executable/Script"});
204         cv.visitSource(sourceName, null);
205
206         mv = cv.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
207         mv.visitCode();
208         mv.visitVarInsn(Opcodes.ALOAD, 0);
209         mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>",
210                 "()V");
211         mv.visitInsn(Opcodes.RETURN);
212         mv.visitMaxs(1, 1);
213         mv.visitEnd();
214
215         // create method for toplevel of script
216
mv = createNewMethod();
217         String JavaDoc className = classname + "$MultiStub" + multiStubCount;
218         String JavaDoc methodName = "method" + multiStubIndex;
219         mv.visitCode();
220
221         try {
222         node.accept(this);
223         } catch (NotCompilableException nce) {
224             // TODO: recover somehow? build a pure eval method?
225
throw nce;
226         }
227
228         mv.visitInsn(Opcodes.ARETURN);
229         mv.visitMaxs(1, 1); // automatically calculated by ASM
230
mv.visitEnd();
231         
232         runtimeLoaded = false;
233         
234         closeOutMultiStub();
235
236         // add Script#run impl
237
mv = cv.visitMethod(Opcodes.ACC_PUBLIC, "run", "(Lorg/jruby/runtime/ThreadContext;Lorg/jruby/runtime/builtin/IRubyObject;)Lorg/jruby/runtime/builtin/IRubyObject;", null, null);
238         mv.visitTypeInsn(Opcodes.NEW, className);
239         mv.visitInsn(Opcodes.DUP);
240         mv.visitMethodInsn(Opcodes.INVOKESPECIAL, className, "<init>", "()V");
241         mv.visitVarInsn(Opcodes.ALOAD, 1);
242         mv.visitVarInsn(Opcodes.ALOAD, 2);
243         mv.visitInsn(Opcodes.ACONST_NULL);
244         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, className, methodName, "(Lorg/jruby/runtime/ThreadContext;Lorg/jruby/runtime/builtin/IRubyObject;[Lorg/jruby/runtime/builtin/IRubyObject;)Lorg/jruby/runtime/builtin/IRubyObject;");
245         mv.visitInsn(Opcodes.ARETURN);
246         mv.visitMaxs(1, 1);
247         mv.visitEnd();
248         
249         return new String JavaDoc[] {className, methodName};
250     }
251     
252     public Class JavaDoc loadClasses(JRubyClassLoader loader) throws ClassNotFoundException JavaDoc {
253         for (Iterator JavaDoc iter = classWriters.entrySet().iterator(); iter.hasNext();) {
254             Map.Entry JavaDoc entry = (Map.Entry JavaDoc)iter.next();
255             String JavaDoc key = (String JavaDoc)entry.getKey();
256             ClassWriter writer = (ClassWriter)entry.getValue();
257             
258             loader.defineClass(key.replaceAll("/", "."), writer.toByteArray());
259         }
260
261         return loader.loadClass(classname.replaceAll("/", "."));
262     }
263
264     // finished
265
public Instruction visitAliasNode(AliasNode iVisited) {
266         lineNumber(iVisited);
267         getRubyClass();
268         mv.visitInsn(Opcodes.DUP);
269         mv.visitInsn(Opcodes.DUP);
270         Label l1 = new Label();
271         mv.visitJumpInsn(Opcodes.IFNONNULL, l1);
272         newTypeError("no class to make alias");
273         mv.visitInsn(Opcodes.ATHROW);
274         
275         mv.visitLabel(l1);
276         loadThreadContext();
277         defineAlias(iVisited.getNewName(), iVisited.getOldName());
278         mv.visitLdcInsn("method_added");
279         newSymbol(iVisited.getNewName());
280         invokeRubyModule("callMethod", "(Lorg/jruby/runtime/ThreadContext;Ljava/lang/String;Lorg/jruby/RubySymbol;)Lorg/jruby/runtime/builtin/IRubyObject;");
281         
282         return null;
283     }
284
285     private void newSymbol(String JavaDoc name) {
286         loadRuntime();
287         mv.visitLdcInsn(name);
288         invokeRuby("newSymbol", "()Lorg/jruby/RubySymbol;");
289     }
290
291     private void defineAlias(String JavaDoc newName, String JavaDoc oldName) {
292         mv.visitLdcInsn(newName);
293         mv.visitLdcInsn(oldName);
294         invokeRubyModule("defineAlias", "(Ljava/lang/String;Ljava/lang/String;)V");
295     }
296
297     private void newTypeError(String JavaDoc error) {
298         loadRuntime();
299         mv.visitLdcInsn(error);
300         invokeRuby("newTypeError", "(Ljava/lang/String;)Lorg/jruby/exceptions/RaiseException;");
301     }
302
303     public Instruction visitAndNode(AndNode iVisited) {
304         lineNumber(iVisited);
305         iVisited.getFirstNode().accept(this);
306         mv.visitInsn(Opcodes.DUP);
307         invokeIRubyObject("isTrue", "()B");
308         Label l1 = new Label();
309         mv.visitJumpInsn(Opcodes.IFEQ, l1);
310         mv.visitInsn(Opcodes.POP); // remove first node's result
311
iVisited.getSecondNode().accept(this);
312         mv.visitLabel(l1);
313         
314         return null;
315     }
316
317     private void invokeIRubyObject(String JavaDoc methodName, String JavaDoc signature) {
318         mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, IRUBYOBJECT, methodName, signature);
319     }
320
321     private void invokeRuby(String JavaDoc methodName, String JavaDoc signature) {
322         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, RUBY, methodName, signature);
323     }
324
325     private void invokeThreadContext(String JavaDoc methodName, String JavaDoc signature) {
326         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, THREADCONTEXT, methodName, signature);
327     }
328
329     private void invokeRubyModule(String JavaDoc methodName, String JavaDoc signature) {
330         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, RUBYMODULE, methodName, signature);
331     }
332
333     public Instruction visitArgsNode(ArgsNode iVisited) {
334         // TODO: this node should never be visited, but it may simplify argument processing if it were
335
return null;
336     }
337
338     public Instruction visitArgsCatNode(ArgsCatNode iVisited) {
339         throw new NotCompilableException("Node not supported: " + iVisited.toString());
340     }
341     
342     private interface ValueCallback {
343         public void putValueOnStack(Object JavaDoc sourceArray, int index);
344     }
345
346     public Instruction visitArrayNode(ArrayNode iVisited) {
347         lineNumber(iVisited);
348         loadRuntime();
349         
350         ValueCallback callback = new ValueCallback() {
351             public void putValueOnStack(Object JavaDoc sourceArray, int index) {
352                 Node node = (Node)((Object JavaDoc[])sourceArray)[index];
353                 node.accept(InstructionCompiler2.this);
354             }
355         };
356         buildObjectArray(IRUBYOBJECT, iVisited.childNodes().toArray(), callback);
357
358         invokeRuby("newArray", "([Lorg/jruby/runtime/builtin/IRubyObject;)Lorg/jruby/RubyArray;");
359         
360         return null;
361     }
362
363     private void buildObjectArray(String JavaDoc type, Object JavaDoc[] sourceArray, ValueCallback callback) {
364         mv.visitLdcInsn(new Integer JavaDoc(sourceArray.length));
365         mv.visitTypeInsn(Opcodes.ANEWARRAY, type);
366         
367         for (int i = 0; i < sourceArray.length; i++) {
368             mv.visitInsn(Opcodes.DUP);
369             mv.visitLdcInsn(new Integer JavaDoc(i));
370             
371             callback.putValueOnStack(sourceArray, i);
372             
373             mv.visitInsn(Opcodes.AASTORE);
374             i++;
375         }
376     }
377
378     private void buildPrimitiveArray(Type type, Object JavaDoc sourceArray, int length, ValueCallback callback) {
379         mv.visitLdcInsn(new Integer JavaDoc(length));
380         mv.visitTypeInsn(Opcodes.NEWARRAY, type.getDescriptor());
381         
382         for (int i = 0; i < length; i++) {
383             mv.visitInsn(Opcodes.DUP);
384             mv.visitLdcInsn(new Integer JavaDoc(i));
385             
386             callback.putValueOnStack(sourceArray, i);
387             
388             if (type.equals(Type.BYTE_TYPE) || type.equals(Type.BOOLEAN_TYPE)) {
389                 mv.visitInsn(Opcodes.BASTORE);
390             } else if (type.equals(Type.CHAR_TYPE)) {
391                 mv.visitInsn(Opcodes.CASTORE);
392             } else if (type.equals(Type.INT_TYPE)) {
393                 mv.visitInsn(Opcodes.IASTORE);
394             } else if (type.equals(Type.LONG_TYPE)) {
395                 mv.visitInsn(Opcodes.LASTORE);
396             } else if (type.equals(Type.FLOAT_TYPE)) {
397                 mv.visitInsn(Opcodes.FASTORE);
398             } else if (type.equals(Type.DOUBLE_TYPE)) {
399                 mv.visitInsn(Opcodes.DASTORE);
400             }
401             i++;
402         }
403     }
404     
405     public Instruction visitArgsPushNode(ArgsPushNode iVisited) {
406         throw new NotCompilableException("Node not supported: " + iVisited.toString());
407     }
408     
409     // FIXME: I just copied logic for CallNode, but the return for this should be lhs of assignment
410
public Instruction visitAttrAssignNode(AttrAssignNode iVisited) {
411         lineNumber(iVisited);
412         loadThreadContext(); // [tc]
413
invokeThreadContext("beginCallArgs", "()V"); // []
414

415         // TODO: try finally around this
416
// recv
417
iVisited.getReceiverNode().accept(this); // [recv]
418

419         // args
420
setupArgs(iVisited.getArgsNode()); // [recv, args]
421

422         loadThreadContext(); // [recv, args, tc]
423
invokeThreadContext("endCallArgs", "()V"); // [recv, args]
424

425         // dup recv for CallType check
426
mv.visitInsn(Opcodes.SWAP);
427         mv.visitInsn(Opcodes.DUP); // [args, recv, recv]
428

429         loadThreadContext();
430         invokeThreadContext("getFrameSelf", "()Lorg/jruby/runtime/builtin/IRubyObject;"); // [args, recv, recv, frameSelf]
431

432         Label l1 = new Label();
433         Label l2 = new Label();
434         
435         // choose CallType appropriately
436
mv.visitJumpInsn(Opcodes.IF_ACMPEQ, l1); // [args, recv]
437
mv.visitFieldInsn(Opcodes.GETSTATIC, "org/jruby/runtime/CallType", "NORMAL", "Lorg/jruby/runtime/CallType;");
438         mv.visitJumpInsn(Opcodes.GOTO, l2);
439         mv.visitLabel(l1);
440         mv.visitFieldInsn(Opcodes.GETSTATIC, "org/jruby/runtime/CallType", "VARIABLE", "Lorg/jruby/runtime/CallType;");
441         mv.visitLabel(l2);
442         
443         // [args, recv, calltype]
444

445         // swap recv and args on stack
446
mv.visitInsn(Opcodes.SWAP); // [args, calltype, recv]
447

448         loadThreadContext(); // [args, calltype, recv, tc]
449
mv.visitInsn(Opcodes.DUP2_X2); // [recv, tc, args, calltype, recv, tc]
450
mv.visitInsn(Opcodes.POP2); // [recv, tc, args, calltype]
451

452         // name to callMethod
453
mv.visitLdcInsn(iVisited.getName()); // [recv, tc, args, calltype, name]
454

455         // put name under args and calltype
456
mv.visitInsn(Opcodes.DUP_X2); // [recv, tc, name, args, calltype, name]
457

458         // pop name on top
459
mv.visitInsn(Opcodes.POP); // [recv, name, args, calltype]
460

461         invokeIRubyObject("callMethod", "(Lorg/jruby/runtime/ThreadContext;Ljava/lang/String;[Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/CallType;)Lorg/jruby/runtime/builtin/IRubyObject;");
462         
463         return null;
464     }
465
466     public Instruction visitBackRefNode(BackRefNode iVisited) {
467         loadThreadContext();
468         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, THREADCONTEXT, "getBackref", "()Lorg/jruby/runtime/builtin/IRubyObject;");
469         Label l1 = new Label();
470         Label l2 = new Label();
471         Label l3 = new Label();
472         Label l4 = new Label();
473         Label l5 = new Label();
474         Label lafter = new Label();
475         mv.visitLookupSwitchInsn(lafter, new int[] { '~', '&', '`', '\\', '+' }, new Label[] { l1, l2, l3, l4, l5 });
476         mv.visitLabel(l1);
477         // ~ do nothing
478
mv.visitJumpInsn(Opcodes.GOTO, lafter);
479         
480         mv.visitLabel(l2);
481         // &
482
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "org/jruby/RubyRegexp", "last_match", "(Lorg/jruby/runtime/builtin/IRubyObject;)Lorg/jruby/runtime/builtin/IRubyObject;");
483         mv.visitJumpInsn(Opcodes.GOTO, lafter);
484         
485         mv.visitLabel(l3);
486         // `
487
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "org/jruby/RubyRegexp", "match_pre", "(Lorg/jruby/runtime/builtin/IRubyObject;)Lorg/jruby/runtime/builtin/IRubyObject;");
488         mv.visitJumpInsn(Opcodes.GOTO, lafter);
489         
490         mv.visitLabel(l4);
491         // \
492
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "org/jruby/RubyRegexp", "match_post", "(Lorg/jruby/runtime/builtin/IRubyObject;)Lorg/jruby/runtime/builtin/IRubyObject;");
493         mv.visitJumpInsn(Opcodes.GOTO, lafter);
494         
495         mv.visitLabel(l5);
496         // +
497
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "org/jruby/RubyRegexp", "match_last", "(Lorg/jruby/runtime/builtin/IRubyObject;)Lorg/jruby/runtime/builtin/IRubyObject;");
498
499         mv.visitLabel(lafter);
500         
501         return null;
502     }
503
504     public Instruction visitBeginNode(BeginNode iVisited) {
505         iVisited.getBodyNode().accept(this);
506         
507         return null;
508     }
509
510     public Instruction visitBignumNode(BignumNode iVisited) {
511         // FIXME: storing the bignum as a string is not as efficient as storing as a byte array
512
lineNumber(iVisited);
513         loadRuntime();
514         mv.visitTypeInsn(Opcodes.NEW, "java/math/BigInteger");
515         mv.visitInsn(Opcodes.DUP);
516         mv.visitLdcInsn(iVisited.getValue().toString());
517         mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/math/BigInteger", "<init>", "(Ljava/lang/String;)V");
518         
519         mv.visitMethodInsn(Opcodes.INVOKESTATIC, "org/jruby/RubyBignum", "newBignum", "(Lorg/jruby/Ruby;Ljava/math/BigInteger;)Lorg/jruby/RubyBignum;");
520         
521         return null;
522     }
523
524     public Instruction visitBlockArgNode(BlockArgNode iVisited) {
525         throw new NotCompilableException("Node not supported: " + iVisited.toString());
526     }
527
528     public Instruction visitBlockNode(BlockNode iVisited) {
529         lineNumber(iVisited);
530         for (Iterator JavaDoc iter = iVisited.childNodes().iterator(); iter.hasNext();) {
531             Node n = (Node)iter.next();
532             
533             n.accept(this);
534             
535             if (iter.hasNext()) {
536                 // clear result from previous line
537
mv.visitInsn(Opcodes.POP);
538             }
539         }
540         
541         return null;
542     }
543
544     public Instruction visitBlockPassNode(BlockPassNode iVisited) {
545         throw new NotCompilableException("Node not supported: " + iVisited.toString());
546     }
547
548     public Instruction visitBreakNode(BreakNode iVisited) {
549         throw new NotCompilableException("Node not supported: " + iVisited.toString());
550     }
551
552     public Instruction visitConstDeclNode(ConstDeclNode iVisited) {
553         // TODO untested
554
lineNumber(iVisited);
555         
556         iVisited.getValueNode().accept(this);
557         
558         if (iVisited.getConstNode() != null) {
559             iVisited.getConstNode().accept(this);
560         } else {
561             getRubyClass();
562             Label l1 = new Label();
563             
564             mv.visitJumpInsn(Opcodes.IFNONNULL, l1);
565             
566             newTypeError("no class/module to define constant");
567             mv.visitInsn(Opcodes.ATHROW);
568             
569             mv.visitLabel(l1);
570             
571             peekCRef();
572         }
573
574         mv.visitTypeInsn(Opcodes.CHECKCAST, RUBYMODULE);
575         
576         mv.visitInsn(Opcodes.SWAP);
577         mv.visitLdcInsn(iVisited.getName());
578         mv.visitInsn(Opcodes.SWAP);
579         invokeRubyModule("setConstant", "(Ljava/lang/String;Lorg/jruby/runtime/builtin/IRubyObject;)Lorg/jruby/runtime/builtin/IRubyObject;");
580         
581         return null;
582     }
583
584     private void peekCRef() {
585         loadThreadContext();
586         invokeThreadContext("peekCRef", "()Lorg/jruby/util/collections/SinglyLinkedList;");
587         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "org/jruby/util/collections/SingleLinkedList", "getValue", "()Ljava/lang/Object;");
588     }
589
590     public Instruction visitClassVarAsgnNode(ClassVarAsgnNode iVisited) {
591         lineNumber(iVisited);
592         
593         // eval value
594
iVisited.getValueNode().accept(this);
595                 
596         getCRefClass();
597         
598         // dup it
599
mv.visitInsn(Opcodes.DUP);
600         
601         Label l1 = new Label();
602         Label l2 = new Label();
603         mv.visitJumpInsn(Opcodes.IFNONNULL, l1);
604         
605         // pop extra null class
606
// FIXME this bit is untested
607
mv.visitInsn(Opcodes.POP);
608         loadSelf();
609         invokeIRubyObject("getMetaClass", "()Lorg/jruby/RubyClass;");
610         mv.visitJumpInsn(Opcodes.GOTO, l2);
611         
612         // FIXME this bit is untested
613
mv.visitLabel(l1);
614         // dup it again
615
mv.visitInsn(Opcodes.DUP);
616         invokeRubyModule("isSingleton", "()Z");
617         mv.visitJumpInsn(Opcodes.IFEQ, l2);
618         
619         mv.visitLdcInsn("__attached__");
620         invokeIRubyObject("getInstanceVariable", "(Ljava/lang/String;)Lorg/jruby/runtime/builtin/IRubyObject;");
621         mv.visitTypeInsn(Opcodes.CHECKCAST, RUBYMODULE);
622         
623         mv.visitLabel(l2);
624         
625         mv.visitInsn(Opcodes.SWAP);
626         mv.visitLdcInsn(iVisited.getName());
627         mv.visitInsn(Opcodes.SWAP);
628         invokeRubyModule("setClassVar", "(Ljava/lang/String;Lorg/jruby/runtime/builtin/IRubyObject;)Lorg/jruby/runtime/builtin/IRubyObject;");
629         
630         return null;
631     }
632
633     public Instruction visitClassVarDeclNode(ClassVarDeclNode iVisited) {
634         // FIXME INCOMPLETE, probably broken
635
lineNumber(iVisited);
636         
637         getRubyClass();
638         Label l298 = new Label();
639         mv.visitJumpInsn(Opcodes.IFNONNULL, l298);
640         newTypeError("no class/module to define class variable");
641         mv.visitInsn(Opcodes.ATHROW);
642         
643         mv.visitLabel(l298);
644         getCRefClass();
645         
646         mv.visitLdcInsn(iVisited.getName());
647         
648         iVisited.getValueNode().accept(this);
649         
650         invokeRubyModule("setClassVar", "(Ljava/lang/String;Lorg/jruby/runtime/builtin/IRubyObject;)V");
651         
652         loadRuntime();
653         invokeRuby("getNil", "()Lorg/jruby/runtime/builtin/IRubyObject;");
654         
655         return null;
656     }
657
658     public Instruction visitClassVarNode(ClassVarNode iVisited) {
659         // TODO untested
660
lineNumber(iVisited);
661         
662         getCRefClass();
663         
664         // dup it
665
mv.visitInsn(Opcodes.DUP);
666         
667         Label l1 = new Label();
668         Label l2 = new Label();
669         mv.visitJumpInsn(Opcodes.IFNONNULL, l1);
670         
671         // pop extra null class
672
mv.visitInsn(Opcodes.POP);
673         loadSelf();
674         invokeIRubyObject("getMetaClass", "()Lorg/jruby/RubyClass;");
675         mv.visitJumpInsn(Opcodes.GOTO, l2);
676         
677         mv.visitLabel(l1);
678         // dup it again
679
mv.visitInsn(Opcodes.DUP);
680         invokeRubyModule("isSingleton", "()Z");
681         mv.visitJumpInsn(Opcodes.IFEQ, l2);
682         
683         mv.visitLdcInsn("__attached__");
684         invokeIRubyObject("getInstanceVariable", "(Ljava/lang/String;)Lorg/jruby/runtime/builtin/IRubyObject;");
685         mv.visitTypeInsn(Opcodes.CHECKCAST, RUBYMODULE);
686         
687         mv.visitLabel(l2);
688         
689         mv.visitLdcInsn(iVisited.getName());
690         invokeRubyModule("getClassVar", "(Ljava/lang/String;)Lorg/jruby/runtime/builtin/IRubyObject;");
691         
692         return null;
693     }
694
695     public Instruction visitCallNode(CallNode iVisited) {
696         lineNumber(iVisited);
697         loadThreadContext(); // [tc]
698
invokeThreadContext("beginCallArgs", "()V"); // []
699

700         // TODO: try finally around this
701
// recv
702
iVisited.getReceiverNode().accept(this); // [recv]
703

704         // args
705
setupArgs(iVisited.getArgsNode()); // [recv, args]
706

707         loadThreadContext(); // [recv, args, tc]
708
invokeThreadContext("endCallArgs", "()V"); // [recv, args]
709

710         // dup recv for CallType check
711
mv.visitInsn(Opcodes.SWAP);
712         mv.visitInsn(Opcodes.DUP); // [args, recv, recv]
713

714         loadThreadContext();
715         invokeThreadContext("getFrameSelf", "()Lorg/jruby/runtime/builtin/IRubyObject;"); // [args, recv, recv, frameSelf]
716

717         Label l1 = new Label();
718         Label l2 = new Label();
719         
720         // choose CallType appropriately
721
mv.visitJumpInsn(Opcodes.IF_ACMPEQ, l1); // [args, recv]
722
mv.visitFieldInsn(Opcodes.GETSTATIC, "org/jruby/runtime/CallType", "NORMAL", "Lorg/jruby/runtime/CallType;");
723         mv.visitJumpInsn(Opcodes.GOTO, l2);
724         mv.visitLabel(l1);
725         mv.visitFieldInsn(Opcodes.GETSTATIC, "org/jruby/runtime/CallType", "VARIABLE", "Lorg/jruby/runtime/CallType;");
726         mv.visitLabel(l2);
727         
728         // [args, recv, calltype]
729

730         // swap recv and args on stack
731
mv.visitInsn(Opcodes.SWAP); // [args, calltype, recv]
732

733         loadThreadContext(); // [args, calltype, recv, tc]
734
mv.visitInsn(Opcodes.DUP2_X2); // [recv, tc, args, calltype, recv, tc]
735
mv.visitInsn(Opcodes.POP2); // [recv, tc, args, calltype]
736

737         // name to callMethod
738
mv.visitLdcInsn(iVisited.getName()); // [recv, tc, args, calltype, name]
739

740         // put name under args and calltype
741
mv.visitInsn(Opcodes.DUP_X2); // [recv, tc, name, args, calltype, name]
742

743         // pop name on top
744
mv.visitInsn(Opcodes.POP); // [recv, name, args, calltype]
745

746         invokeIRubyObject("callMethod", "(Lorg/jruby/runtime/ThreadContext;Ljava/lang/String;[Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/CallType;)Lorg/jruby/runtime/builtin/IRubyObject;");
747         
748         return null;
749     }
750
751     public Instruction visitCaseNode(CaseNode iVisited) {
752         throw new NotCompilableException("Node not supported: " + iVisited.toString());
753     }
754
755     public Instruction visitClassNode(ClassNode iVisited) {
756         throw new NotCompilableException("Node not supported: " + iVisited.toString());
757     }
758
759     public Instruction visitColon2Node(Colon2Node iVisited) {
760         throw new NotCompilableException("Node not supported: " + iVisited.toString());
761     }
762
763     public Instruction visitColon3Node(Colon3Node iVisited) {
764         throw new NotCompilableException("Node not supported: " + iVisited.toString());
765     }
766
767     public Instruction visitConstNode(ConstNode iVisited) {
768         lineNumber(iVisited);
769         
770         loadThreadContext();
771         mv.visitLdcInsn(iVisited.getName());
772         invokeThreadContext("getConstant", "(Ljava/lang/String;)Lorg/jruby/runtime/builtin/IRubyObject;");
773         
774         return null;
775     }
776
777     public Instruction visitDAsgnNode(DAsgnNode iVisited) {
778         throw new NotCompilableException("Node not supported: " + iVisited.toString());
779     }
780
781     public Instruction visitDRegxNode(DRegexpNode iVisited) {
782         throw new NotCompilableException("Node not supported: " + iVisited.toString());
783     }
784
785     public Instruction visitDStrNode(DStrNode iVisited) {
786         throw new NotCompilableException("Node not supported: " + iVisited.toString());
787     }
788
789     public Instruction visitDSymbolNode(DSymbolNode iVisited) {
790         throw new NotCompilableException("Node not supported: " + iVisited.toString());
791     }
792
793     public Instruction visitDVarNode(DVarNode iVisited) {
794         throw new NotCompilableException("Node not supported: " + iVisited.toString());
795     }
796
797     public Instruction visitDXStrNode(DXStrNode iVisited) {
798         throw new NotCompilableException("Node not supported: " + iVisited.toString());
799     }
800
801     public Instruction visitDefinedNode(DefinedNode iVisited) {
802         throw new NotCompilableException("Node not supported: " + iVisited.toString());
803     }
804
805     public MethodVisitor createNewMethod() {
806         // create a new MultiStub-based method impl and provide the method visitor for it
807
if (currentMultiStub == null || multiStubIndex == 9) {
808             if (currentMultiStub != null) {
809                 // FIXME can we end if there's still a method in flight?
810
currentMultiStub.visitEnd();
811             }
812             
813             multiStubCount++;
814             
815             currentMultiStub = new ClassWriter(true);
816             currentMultiStub.visit(Opcodes.V1_2, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER + Opcodes.ACC_STATIC,
817                     classname + "$MultiStub" + multiStubCount, null, "java/lang/Object", new String JavaDoc[] {"org/jruby/internal/runtime/methods/MultiStub"});
818             cv.visitInnerClass(classname + "$MultiStub" + multiStubCount, classname, "MultiStub" + multiStubCount, Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC);
819             multiStubIndex = 0;
820             classWriters.put(classname + "$MultiStub" + multiStubCount, currentMultiStub);
821             currentMultiStub.visitSource(sourceName, null);
822
823             MethodVisitor stubConstructor = currentMultiStub.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
824             stubConstructor.visitCode();
825             stubConstructor.visitVarInsn(Opcodes.ALOAD, 0);
826             stubConstructor.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>",
827                     "()V");
828             stubConstructor.visitInsn(Opcodes.RETURN);
829             stubConstructor.visitMaxs(1, 1);
830             stubConstructor.visitEnd();
831         } else {
832             multiStubIndex++;
833         }
834         
835         return currentMultiStub.visitMethod(Opcodes.ACC_PUBLIC, "method" + multiStubIndex, "(Lorg/jruby/runtime/ThreadContext;Lorg/jruby/runtime/builtin/IRubyObject;[Lorg/jruby/runtime/builtin/IRubyObject;)Lorg/jruby/runtime/builtin/IRubyObject;", null, null);
836     }
837
838     public Instruction visitDefnNode(DefnNode iVisited) {
839         // TODO: build arg list based on number of args, optionals, etc
840
MethodVisitor oldMethod = mv;
841         boolean oldRuntimeLoaded = runtimeLoaded;
842         
843         runtimeLoaded = false;
844         
845         mv = createNewMethod();
846         mv.visitCode();
847         
848         // TODO: this probably isn't always an ArgsNode
849
args = (ArgsNode)iVisited.getArgsNode();
850         
851         mv.visitLdcInsn(new Integer JavaDoc(iVisited.getScope().getNumberOfVariables()));
852         mv.visitTypeInsn(Opcodes.ANEWARRAY, "org/jruby/runtime/builtin/IRubyObject");
853         mv.visitInsn(Opcodes.DUP);
854         // FIXME: use constant for index of local vars
855
mv.visitVarInsn(Opcodes.ASTORE, 4);
856         mv.visitVarInsn(Opcodes.ALOAD, 3);
857         mv.visitInsn(Opcodes.SWAP);
858         mv.visitLdcInsn(new Integer JavaDoc(0));
859         mv.visitInsn(Opcodes.SWAP);
860         mv.visitLdcInsn(new Integer JavaDoc(0));
861         mv.visitLdcInsn(new Integer JavaDoc(args.getArity().getValue()));
862         mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System", "arraycopy", "(Ljava/lang/Object;ILjava/lang/Object;II)V");
863         
864         try {
865             iVisited.getBodyNode().accept(this);
866         } catch (NotCompilableException nce) {
867             // TODO: recover somehow? build a pure eval method?
868
throw nce;
869         }
870
871         mv.visitMaxs(1, 1); // automatically calculated by ASM
872
mv.visitInsn(Opcodes.ARETURN);
873         mv.visitEnd();
874         
875         runtimeLoaded = oldRuntimeLoaded;
876         
877         mv = oldMethod;
878         
879         // method compiled, add to class
880
getRubyClass();
881         Label l335 = new Label();
882         // if class is null, throw error
883
mv.visitJumpInsn(Opcodes.IFNONNULL, l335);
884         newTypeError("No class to add method.");
885         mv.visitInsn(Opcodes.ATHROW);
886         mv.visitLabel(l335);
887         
888         Label l338 = new Label();
889         
890         // only do Object#initialize check if necessary
891
if (iVisited.getName().equals("initialize")) {
892             // got class, compare to Object
893
getRubyClass();
894             loadRuntime();
895             invokeRuby("getObject", "()Lorg/jruby/RubyClass;");
896             // if class == Object
897
mv.visitJumpInsn(Opcodes.IF_ACMPNE, l338);
898             loadRuntime();
899             // display warning about redefining Object#initialize
900
invokeRuby("getWarnings", "()Lorg/jruby/common/RubyWarnings;");
901             mv.visitLdcInsn("redefining Object#initialize may cause infinite loop");
902             mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "org/jruby/common/RubyWarnings", "warn", "(Ljava/lang/String;)V");
903         }
904         
905         mv.visitLabel(l338);
906         // TODO: fix this section for initialize visibility
907
// mv.visitLdcInsn(iVisited.getName());
908
// mv.visitLdcInsn("initialize");
909
// mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z");
910
// Label l341 = new Label();
911
// mv.visitJumpInsn(Opcodes.IFNE, l341);
912
// getCurrentVisibility();
913
// mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "org/jruby/runtime/Visibility", "isModuleFunction", "()Z");
914
// Label l342 = new Label();
915
// mv.visitJumpInsn(Opcodes.IFEQ, l342);
916
// mv.visitLabel(l341);
917
// mv.visitFieldInsn(Opcodes.GETSTATIC, "org/jruby/runtime/Visibility", "PRIVATE", "Lorg/jruby/runtime/Visibility;");
918
// mv.visitVarInsn(ASTORE, 7);
919
// mv.visitLabel(l342);
920
getRubyClass();
921         mv.visitTypeInsn(Opcodes.NEW, "org/jruby/internal/runtime/methods/MultiStubMethod");
922         mv.visitInsn(Opcodes.DUP);
923         mv.visitTypeInsn(Opcodes.NEW, classname + "$MultiStub" + multiStubCount);
924         mv.visitInsn(Opcodes.DUP);
925         mv.visitMethodInsn(Opcodes.INVOKESPECIAL, classname + "$MultiStub" + multiStubCount, "<init>", "()V");
926         mv.visitLdcInsn(new Integer JavaDoc(multiStubIndex));
927         getRubyClass();
928         // TODO: handle args some way? maybe unnecessary with method compiled?
929
// mv.visitVarInsn(ALOAD, 4);
930
// mv.visitMethodInsn(INVOKEVIRTUAL, "org/jruby/ast/DefnNode", "getArgsNode", "()Lorg/jruby/ast/Node;");
931
// mv.visitTypeInsn(CHECKCAST, "org/jruby/ast/ArgsNode");
932
mv.visitLdcInsn(new Integer JavaDoc(args.getArity().getValue()));
933         mv.visitMethodInsn(Opcodes.INVOKESTATIC, "org/jruby/runtime/Arity", "createArity", "(I)Lorg/jruby/runtime/Arity;");
934         getCurrentVisibility();
935         mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "org/jruby/internal/runtime/methods/MultiStubMethod", "<init>", "(Lorg/jruby/internal/runtime/methods/MultiStub;ILorg/jruby/RubyModule;Lorg/jruby/runtime/Arity;Lorg/jruby/runtime/Visibility;)V");
936         
937         mv.visitLdcInsn(iVisited.getName());
938         // put name before MultiStubMethod instance
939
mv.visitInsn(Opcodes.SWAP);
940         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "org/jruby/RubyModule", "addMethod", "(Ljava/lang/String;Lorg/jruby/runtime/ICallable;)V");
941         // FIXME: this part is for invoking method_added or singleton_method_added
942
// Label l345 = new Label();
943
// mv.visitLabel(l345);
944
// mv.visitLineNumber(538, l345);
945
// loadThreadContext();
946
// mv.visitMethodInsn(INVOKEVIRTUAL, "org/jruby/runtime/ThreadContext", "getCurrentVisibility", "()Lorg/jruby/runtime/Visibility;");
947
// mv.visitMethodInsn(INVOKEVIRTUAL, "org/jruby/runtime/Visibility", "isModuleFunction", "()Z");
948
// Label l346 = new Label();
949
// mv.visitJumpInsn(IFEQ, l346);
950
// Label l347 = new Label();
951
// mv.visitLabel(l347);
952
// mv.visitLineNumber(539, l347);
953
// mv.visitVarInsn(ALOAD, 5);
954
// mv.visitMethodInsn(INVOKEVIRTUAL, "org/jruby/RubyModule", "getSingletonClass", "()Lorg/jruby/MetaClass;");
955
// mv.visitLdcInsn(iVisited.getName());
956
// mv.visitTypeInsn(NEW, "org/jruby/internal/runtime/methods/WrapperCallable");
957
// mv.visitInsn(DUP);
958
// mv.visitVarInsn(ALOAD, 5);
959
// mv.visitMethodInsn(INVOKEVIRTUAL, "org/jruby/RubyModule", "getSingletonClass", "()Lorg/jruby/MetaClass;");
960
// mv.visitVarInsn(ALOAD, 8);
961
// mv.visitFieldInsn(GETSTATIC, "org/jruby/runtime/Visibility", "PUBLIC", "Lorg/jruby/runtime/Visibility;");
962
// mv.visitMethodInsn(INVOKESPECIAL, "org/jruby/internal/runtime/methods/WrapperCallable", "<init>", "(Lorg/jruby/RubyModule;Lorg/jruby/runtime/ICallable;Lorg/jruby/runtime/Visibility;)V");
963
// mv.visitMethodInsn(INVOKEVIRTUAL, "org/jruby/MetaClass", "addMethod", "(Ljava/lang/String;Lorg/jruby/runtime/ICallable;)V");
964
// Label l348 = new Label();
965
// mv.visitLabel(l348);
966
// mv.visitLineNumber(543, l348);
967
// mv.visitVarInsn(ALOAD, 5);
968
// mv.visitLdcInsn("singleton_method_added");
969
// loadRuntime();
970
// mv.visitLdcInsn(iVisited.getName());
971
// invokeIRuby("newSymbol", "(Ljava/lang/String;)Lorg/jruby/RubySymbol;");
972
// mv.visitMethodInsn(INVOKEVIRTUAL, "org/jruby/RubyModule", "callMethod", "(Lorg/jruby/runtime/ThreadContext;Ljava/lang/String;Lorg/jruby/runtime/builtin/IRubyObject;)Lorg/jruby/runtime/builtin/IRubyObject;");
973
// mv.visitInsn(POP);
974
// mv.visitLabel(l346);
975
// mv.visitLineNumber(547, l346);
976
// mv.visitVarInsn(ALOAD, 5);
977
// mv.visitMethodInsn(INVOKEVIRTUAL, "org/jruby/RubyModule", "isSingleton", "()Z");
978
// Label l349 = new Label();
979
// mv.visitJumpInsn(IFEQ, l349);
980
// Label l350 = new Label();
981
// mv.visitLabel(l350);
982
// mv.visitLineNumber(548, l350);
983
// mv.visitVarInsn(ALOAD, 5);
984
// mv.visitTypeInsn(CHECKCAST, "org/jruby/MetaClass");
985
// mv.visitMethodInsn(INVOKEVIRTUAL, "org/jruby/MetaClass", "getAttachedObject", "()Lorg/jruby/runtime/builtin/IRubyObject;");
986
// mv.visitLdcInsn("singleton_method_added");
987
// loadRuntime();
988
// mv.visitVarInsn(ALOAD, 4);
989
// mv.visitMethodInsn(INVOKEVIRTUAL, "org/jruby/ast/DefnNode", "getName", "()Ljava/lang/String;");
990
// invokeIRuby("newSymbol", "(Ljava/lang/String;)Lorg/jruby/RubySymbol;");
991
// mv.visitMethodInsn(INVOKEINTERFACE, "org/jruby/runtime/builtin/IRubyObject", "callMethod", "(Lorg/jruby/runtime/ThreadContext;Ljava/lang/String;Lorg/jruby/runtime/builtin/IRubyObject;)Lorg/jruby/runtime/builtin/IRubyObject;");
992
// mv.visitInsn(POP);
993
// Label l351 = new Label();
994
// mv.visitJumpInsn(GOTO, l351);
995
// mv.visitLabel(l349);
996
// mv.visitLineNumber(551, l349);
997
// mv.visitVarInsn(ALOAD, 5);
998
// mv.visitLdcInsn("method_added");
999
// loadRuntime();
1000
// mv.visitLdcInsn(iVisited.getName());
1001
// invokeIRuby("newSymbol", "(Ljava/lang/String;)Lorg/jruby/RubySymbol;");
1002
// mv.visitMethodInsn(INVOKEVIRTUAL, "org/jruby/RubyModule", "callMethod", "(Lorg/jruby/runtime/ThreadContext;Ljava/lang/String;Lorg/jruby/runtime/builtin/IRubyObject;)Lorg/jruby/runtime/builtin/IRubyObject;");
1003
// mv.visitInsn(POP);
1004
// mv.visitLabel(l351);
1005
// mv.visitLineNumber(554, l351);
1006
loadRuntime();
1007        invokeRuby("getNil", "()Lorg/jruby/runtime/builtin/IRubyObject;");
1008        
1009        return null;
1010    }
1011
1012    private void getCurrentVisibility() {
1013        loadThreadContext();
1014        invokeThreadContext("getCurrentVisibility", "()Lorg/jruby/runtime/Visibility;");
1015    }
1016
1017    public Instruction visitDefsNode(DefsNode iVisited) {
1018        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1019    }
1020
1021    public Instruction visitDotNode(DotNode iVisited) {
1022        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1023    }
1024
1025    public Instruction visitEnsureNode(EnsureNode iVisited) {
1026        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1027    }
1028
1029    public Instruction visitEvStrNode(EvStrNode iVisited) {
1030        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1031    }
1032
1033    public Instruction visitFCallNode(FCallNode iVisited) {
1034        lineNumber(iVisited);
1035        loadThreadContext();
1036        invokeThreadContext("getFrameSelf", "()Lorg/jruby/runtime/builtin/IRubyObject;"); // [frameSelf]
1037

1038        mv.visitLdcInsn(iVisited.getName()); // [frameSelf, name]
1039

1040        loadThreadContext(); // [frameSelf, name, tc]
1041
invokeThreadContext("beginCallArgs", "()V"); // [frameSelf, name]
1042

1043        // args
1044
setupArgs(iVisited.getArgsNode()); // [frameSelf, name, args]
1045

1046        loadThreadContext();
1047        invokeThreadContext("endCallArgs", "()V"); // [frameSelf, name, args]
1048

1049        loadThreadContext();
1050        mv.visitInsn(Opcodes.DUP_X2); // [frameSelf, tc, name, args, tc]
1051
mv.visitInsn(Opcodes.POP); // [frameSelf, tc, name, args]
1052

1053        mv.visitFieldInsn(Opcodes.GETSTATIC, "org/jruby/runtime/CallType", "FUNCTIONAL", "Lorg/jruby/runtime/CallType;"); // [frameSelf, tc, name, args, calltype]
1054

1055        invokeIRubyObject("callMethod", "(Lorg/jruby/runtime/ThreadContext;Ljava/lang/String;[Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/CallType;)Lorg/jruby/runtime/builtin/IRubyObject;");
1056        
1057        return null;
1058    }
1059
1060    public Instruction visitFalseNode(FalseNode iVisited) {
1061        lineNumber(iVisited);
1062        loadRuntime();
1063        invokeRuby("getFalse", "()Lorg/jruby/RubyBoolean;");
1064        
1065        return null;
1066    }
1067
1068    public Instruction visitFixnumNode(FixnumNode iVisited) {
1069        lineNumber(iVisited);
1070        loadThreadContext();
1071        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
1072                THREADCONTEXT, "getRuntime",
1073                "()Lorg/jruby/Ruby;");
1074        mv.visitLdcInsn(new Long JavaDoc(iVisited.getValue()));
1075        invokeRuby("newFixnum", "(J)Lorg/jruby/RubyFixnum;");
1076
1077        return null;
1078    }
1079
1080    public Instruction visitFlipNode(FlipNode iVisited) {
1081        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1082    }
1083
1084    public Instruction visitFloatNode(FloatNode iVisited) {
1085        lineNumber(iVisited);
1086        loadRuntime();
1087        mv.visitLdcInsn(new Double JavaDoc(iVisited.getValue()));
1088        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "org/jruby/RubyFloat", "newFloat", "(Lorg/jruby/Ruby;D)Lorg/jruby/RubyFloat;");
1089        
1090        return null;
1091    }
1092
1093    public Instruction visitForNode(ForNode iVisited) {
1094        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1095    }
1096
1097    public Instruction visitGlobalAsgnNode(GlobalAsgnNode iVisited) {
1098        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1099    }
1100
1101    public Instruction visitGlobalVarNode(GlobalVarNode iVisited) {
1102        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1103    }
1104
1105    public Instruction visitHashNode(HashNode iVisited) {
1106        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1107    }
1108
1109    public Instruction visitInstAsgnNode(InstAsgnNode iVisited) {
1110        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1111    }
1112
1113    public Instruction visitInstVarNode(InstVarNode iVisited) {
1114        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1115    }
1116
1117    public Instruction visitIfNode(IfNode iVisited) {
1118        lineNumber(iVisited);
1119        Label afterJmp = new Label();
1120        Label falseJmp = new Label();
1121
1122        // visit condition
1123
iVisited.getCondition().accept(this);
1124
1125        // call isTrue on the result
1126
invokeIRubyObject("isTrue", "()Z");
1127        mv.visitJumpInsn(Opcodes.IFEQ, falseJmp); // EQ == 0 (i.e. false)
1128
iVisited.getThenBody().accept(this);
1129        mv.visitJumpInsn(Opcodes.GOTO, afterJmp);
1130
1131        mv.visitLabel(falseJmp);
1132        iVisited.getElseBody().accept(this);
1133
1134        mv.visitLabel(afterJmp);
1135
1136        return null;
1137    }
1138
1139    public Instruction visitIterNode(IterNode iVisited) {
1140        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1141    }
1142
1143    public Instruction visitLocalAsgnNode(LocalAsgnNode iVisited) {
1144        lineNumber(iVisited);
1145        
1146        iVisited.getValueNode().accept(this);
1147        mv.visitInsn(Opcodes.DUP);
1148        mv.visitVarInsn(Opcodes.ALOAD, 4);
1149        mv.visitInsn(Opcodes.SWAP);
1150        mv.visitLdcInsn(new Integer JavaDoc(iVisited.getIndex()));
1151        mv.visitInsn(Opcodes.SWAP);
1152        mv.visitInsn(Opcodes.AASTORE);
1153        
1154        return null;
1155    }
1156
1157    public Instruction visitLocalVarNode(LocalVarNode iVisited) {
1158        lineNumber(iVisited);
1159        // check if it's an argument
1160
int index = iVisited.getIndex();
1161        
1162        if (args != null && (index - 2) < args.getArgsCount()) {
1163            // load from the incoming params
1164
// index is 2-based, and our zero is runtime
1165

1166            // load args array
1167
mv.visitVarInsn(Opcodes.ALOAD, 3);
1168            mv.visitLdcInsn(new Integer JavaDoc(index - 2));
1169            mv.visitInsn(Opcodes.AALOAD);
1170        } else {
1171            mv.visitVarInsn(Opcodes.ALOAD, 4);
1172            mv.visitLdcInsn(new Integer JavaDoc(iVisited.getIndex()));
1173            mv.visitInsn(Opcodes.AALOAD);
1174        }
1175        return null;
1176    }
1177
1178    public Instruction visitMultipleAsgnNode(MultipleAsgnNode iVisited) {
1179        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1180    }
1181
1182    public Instruction visitMatch2Node(Match2Node iVisited) {
1183        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1184    }
1185
1186    public Instruction visitMatch3Node(Match3Node iVisited) {
1187        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1188    }
1189
1190    public Instruction visitMatchNode(MatchNode iVisited) {
1191        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1192    }
1193
1194    public Instruction visitModuleNode(ModuleNode iVisited) {
1195        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1196    }
1197
1198    public Instruction visitNewlineNode(NewlineNode iVisited) {
1199        // TODO: add trace call
1200

1201        iVisited.getNextNode().accept(this);
1202
1203        return null;
1204    }
1205
1206    public Instruction visitNextNode(NextNode iVisited) {
1207        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1208    }
1209
1210    public Instruction visitNilNode(NilNode iVisited) {
1211        lineNumber(iVisited);
1212        loadRuntime();
1213        invokeRuby("getNil", "()Lorg/jruby/runtime/builtin/IRubyObject;");
1214        
1215        return null;
1216    }
1217
1218    public Instruction visitNotNode(NotNode iVisited) {
1219        lineNumber(iVisited);
1220        loadRuntime();
1221        iVisited.getConditionNode().accept(this);
1222        invokeIRubyObject("isTrue", "()B");
1223        Label l1 = new Label();
1224        Label l2 = new Label();
1225        mv.visitJumpInsn(Opcodes.IFEQ, l1);
1226        invokeRuby("getFalse", "()Lorg/jruby/RubyBoolean;");
1227        mv.visitLabel(l1);
1228        invokeRuby("getTrue", "()Lorg/jruby/RubyBoolean;");
1229        mv.visitLabel(l2);
1230        
1231        return null;
1232    }
1233
1234    public Instruction visitNthRefNode(NthRefNode iVisited) {
1235        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1236    }
1237
1238    public Instruction visitOpElementAsgnNode(OpElementAsgnNode iVisited) {
1239        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1240    }
1241
1242    public Instruction visitOpAsgnNode(OpAsgnNode iVisited) {
1243        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1244    }
1245
1246    public Instruction visitOpAsgnAndNode(OpAsgnAndNode iVisited) {
1247        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1248    }
1249
1250    public Instruction visitOpAsgnOrNode(OpAsgnOrNode iVisited) {
1251        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1252    }
1253
1254    public Instruction visitOptNNode(OptNNode iVisited) {
1255        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1256    }
1257
1258    public Instruction visitOrNode(OrNode iVisited) {
1259        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1260    }
1261
1262    public Instruction visitPostExeNode(PostExeNode iVisited) {
1263        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1264    }
1265
1266    public Instruction visitRedoNode(RedoNode iVisited) {
1267        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1268    }
1269
1270    public Instruction visitRegexpNode(RegexpNode iVisited) {
1271        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1272    }
1273
1274    public Instruction visitRescueBodyNode(RescueBodyNode iVisited) {
1275        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1276    }
1277
1278    public Instruction visitRescueNode(RescueNode iVisited) {
1279        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1280    }
1281
1282    public Instruction visitRetryNode(RetryNode iVisited) {
1283        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1284    }
1285
1286    public Instruction visitReturnNode(ReturnNode iVisited) {
1287        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1288    }
1289    
1290    public Instruction visitRootNode(RootNode iVisited) {
1291        mv.visitLdcInsn(new Integer JavaDoc(iVisited.getStaticScope().getNumberOfVariables()));
1292        mv.visitTypeInsn(Opcodes.ANEWARRAY, "org/jruby/runtime/builtin/IRubyObject");
1293        // FIXME: use constant for index of local vars
1294
mv.visitVarInsn(Opcodes.ASTORE, 4);
1295        
1296        iVisited.getBodyNode().accept(this);
1297        
1298        return null;
1299    }
1300
1301    public Instruction visitSClassNode(SClassNode iVisited) {
1302        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1303    }
1304
1305    public Instruction visitSelfNode(SelfNode iVisited) {
1306        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1307    }
1308
1309    public Instruction visitSplatNode(SplatNode iVisited) {
1310        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1311    }
1312
1313    public Instruction visitStrNode(StrNode iVisited) {
1314        lineNumber(iVisited);
1315        loadRuntime();
1316        mv.visitLdcInsn(iVisited.getValue());
1317        invokeRuby("newString", "(Ljava/lang/String;)Lorg/jruby/RubyString;");
1318        
1319        return null;
1320    }
1321
1322    public Instruction visitSuperNode(SuperNode iVisited) {
1323        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1324    }
1325
1326    public Instruction visitSValueNode(SValueNode iVisited) {
1327        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1328    }
1329
1330    public Instruction visitSymbolNode(SymbolNode iVisited) {
1331        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1332    }
1333
1334    public Instruction visitToAryNode(ToAryNode iVisited) {
1335        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1336    }
1337
1338    public Instruction visitTrueNode(TrueNode iVisited) {
1339        lineNumber(iVisited);
1340        loadRuntime();
1341        invokeRuby("getTrue", "()Lorg/jruby/RubyBoolean;");
1342        
1343        return null;
1344    }
1345
1346    public Instruction visitUndefNode(UndefNode iVisited) {
1347        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1348    }
1349
1350    public Instruction visitUntilNode(UntilNode iVisited) {
1351        lineNumber(iVisited);
1352        
1353        // FIXME support next, break, etc
1354

1355        // leave nil on the stack when we're done
1356
loadRuntime();
1357        invokeRuby("getNil", "()Lorg/jruby/runtime/builtin/IRubyObject;");
1358        
1359        if (iVisited.getBodyNode() != null) {
1360            Label l1 = new Label();
1361            Label l2 = new Label();
1362            
1363            mv.visitLabel(l1);
1364            
1365            iVisited.getConditionNode().accept(this);
1366            invokeIRubyObject("isTrue", "()Z");
1367            // conditionally jump end for until
1368
mv.visitJumpInsn(Opcodes.IFNE, l2);
1369            
1370            iVisited.getBodyNode().accept(this);
1371            // clear last result
1372
mv.visitInsn(Opcodes.POP);
1373            
1374            // jump back for until
1375
mv.visitJumpInsn(Opcodes.GOTO, l1);
1376            
1377            mv.visitLabel(l2);
1378    }
1379
1380        return null;
1381    }
1382
1383    public Instruction visitVAliasNode(VAliasNode iVisited) {
1384        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1385    }
1386
1387    public Instruction visitVCallNode(VCallNode iVisited) {
1388        lineNumber(iVisited);
1389        loadSelf();
1390        loadThreadContext();
1391        
1392        mv.visitLdcInsn(iVisited.getName());
1393
1394        mv.visitFieldInsn(Opcodes.GETSTATIC, "org/jruby/runtime/builtin/IRubyObject", "NULL_ARRAY", "[Lorg/jruby/runtime/builtin/IRubyObject;");
1395        mv.visitFieldInsn(Opcodes.GETSTATIC, "org/jruby/runtime/CallType", "FUNCTIONAL", "Lorg/jruby/runtime/CallType;");
1396        
1397        invokeIRubyObject("callMethod", "(Lorg/jruby/runtime/ThreadContext;Ljava/lang/String;[Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/CallType;)Lorg/jruby/runtime/builtin/IRubyObject;");
1398        
1399        return null;
1400    }
1401
1402    public Instruction visitWhenNode(WhenNode iVisited) {
1403        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1404    }
1405
1406    public Instruction visitWhileNode(WhileNode iVisited) {
1407        lineNumber(iVisited);
1408        
1409        // leave nil on the stack when we're done
1410
loadRuntime();
1411        invokeRuby("getNil", "()Lorg/jruby/runtime/builtin/IRubyObject;");
1412        
1413        if (iVisited.getBodyNode() != null) {
1414            Label l1 = new Label();
1415            Label l2 = new Label();
1416            
1417            mv.visitLabel(l1);
1418            
1419            if (iVisited.evaluateAtStart()) {
1420                iVisited.getConditionNode().accept(this);
1421                invokeIRubyObject("isTrue", "()Z");
1422                // conditionally jump end for while
1423
mv.visitJumpInsn(Opcodes.IFEQ, l2);
1424            }
1425            
1426            iVisited.getBodyNode().accept(this);
1427            // clear last result
1428
mv.visitInsn(Opcodes.POP);
1429            
1430            if (!iVisited.evaluateAtStart()) {
1431                iVisited.getConditionNode().accept(this);
1432                invokeIRubyObject("isTrue", "()Z");
1433                // conditionally jump back for do...while
1434
mv.visitJumpInsn(Opcodes.IFNE, l1);
1435            } else {
1436                // jump back for while
1437
mv.visitJumpInsn(Opcodes.GOTO, l1);
1438            }
1439            
1440            mv.visitLabel(l2);
1441        }
1442        
1443        return null;
1444    }
1445
1446    public Instruction visitXStrNode(XStrNode iVisited) {
1447        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1448    }
1449
1450    public Instruction visitYieldNode(YieldNode iVisited) {
1451        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1452    }
1453
1454    public Instruction visitZArrayNode(ZArrayNode iVisited) {
1455        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1456    }
1457
1458    public Instruction visitZSuperNode(ZSuperNode iVisited) {
1459        throw new NotCompilableException("Node not supported: " + iVisited.toString());
1460    }
1461
1462    private void lineNumber(Node iVisited) {
1463        if (!EXPERIMENTAL_SOURCING) {
1464            return;
1465        }
1466        if (lastLine == (lastLine = iVisited.getPosition().getEndLine())) return; // did not change lines for this node, don't bother relabeling
1467

1468        Label l = new Label();
1469        mv.visitLabel(l);
1470        mv.visitLineNumber(iVisited.getPosition().getEndLine(), l);
1471    }
1472
1473    public Map JavaDoc getClassWriters() {
1474        return classWriters;
1475    }
1476    
1477    private void setupArgs(Node node) {
1478        if (node == null) {
1479            mv.visitInsn(Opcodes.ICONST_0);
1480            mv.visitTypeInsn(Opcodes.ANEWARRAY, IRUBYOBJECT);
1481        } else if (node instanceof ArrayNode) {
1482            lineNumber(node);
1483            int count = ((ArrayNode)node).size();
1484            mv.visitLdcInsn(new Integer JavaDoc(count));
1485            mv.visitTypeInsn(Opcodes.ANEWARRAY, IRUBYOBJECT);
1486            
1487            int i = 0;
1488            for (Iterator JavaDoc iter = ((ArrayNode) node).iterator(); iter.hasNext();) {
1489                final Node next = (Node) iter.next();
1490                
1491                mv.visitInsn(Opcodes.DUP);
1492                mv.visitLdcInsn(new Integer JavaDoc(i));
1493                
1494                // FIXME: implement splatnode logic to make appropriate count
1495
if (next instanceof SplatNode) {
1496                    //count += getSplatNodeSize((SplatNode)next) - 1;
1497
} else {
1498                    next.accept(this);
1499                }
1500                
1501                mv.visitInsn(Opcodes.AASTORE);
1502                i++;
1503            }
1504        }
1505    }
1506
1507    private void loadThreadContext() {
1508        // FIXME: make this work correctly for non-static, non-singleton
1509
mv.visitVarInsn(Opcodes.ALOAD, 1);
1510        }
1511
1512    private void loadRuntime() {
1513        // FIXME: make this work correctly for non-static, non-singleton
1514
// if (runtimeLoaded) {
1515
// mv.visitVarInsn(Opcodes.ALOAD, 50);
1516
// return;
1517
// }
1518
// load ThreadContext param
1519
mv.visitVarInsn(Opcodes.ALOAD, 1);
1520        invokeThreadContext("getRuntime", "()Lorg/jruby/Ruby;");
1521// mv.visitInsn(Opcodes.DUP);
1522
// mv.visitVarInsn(Opcodes.ASTORE, 50);
1523
// // FIXME find a better way of caching, since the path that caches may be conditional
1524
// runtimeLoaded = false;
1525
}
1526
1527    private void loadSelf() {
1528        mv.visitVarInsn(Opcodes.ALOAD, 2);
1529    }
1530
1531    private void getCRefClass() {
1532        loadThreadContext();
1533        invokeThreadContext("peekCRef", "()Lorg/jruby/util/collections/SinglyLinkedList;");
1534        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "org/jruby/util/collections/SinglyLinkedList", "getValue", "()Ljava/lang/Object;");
1535        mv.visitTypeInsn(Opcodes.CHECKCAST, RUBYMODULE);
1536}
1537    private void getRubyClass() {
1538        loadThreadContext();
1539        invokeThreadContext("getRubyClass", "()Lorg/jruby/RubyModule;");
1540    }
1541}
1542
Popular Tags