001: /***** BEGIN LICENSE BLOCK *****
002: * Version: CPL 1.0/GPL 2.0/LGPL 2.1
003: *
004: * The contents of this file are subject to the Common Public
005: * License Version 1.0 (the "License"); you may not use this file
006: * except in compliance with the License. You may obtain a copy of
007: * the License at http://www.eclipse.org/legal/cpl-v10.html
008: *
009: * Software distributed under the License is distributed on an "AS
010: * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
011: * implied. See the License for the specific language governing
012: * rights and limitations under the License.
013: *
014: * Copyright (C) 2007 Ola Bini <ola@ologix.com>
015: *
016: * Alternatively, the contents of this file may be used under the terms of
017: * either of the GNU General Public License Version 2 or later (the "GPL"),
018: * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
019: * in which case the provisions of the GPL or the LGPL are applicable instead
020: * of those above. If you wish to allow use of your version of this file only
021: * under the terms of either the GPL or the LGPL, and not to allow others to
022: * use your version of this file under the terms of the CPL, indicate your
023: * decision by deleting the provisions above and replace them with the notice
024: * and other provisions required by the GPL or the LGPL. If you do not delete
025: * the provisions above, a recipient may use your version of this file under
026: * the terms of any one of the CPL, the GPL or the LGPL.
027: ***** END LICENSE BLOCK *****/package org.jruby.compiler.yarv;
028:
029: import java.util.List;
030: import java.util.ArrayList;
031: import java.util.Iterator;
032: import java.util.Map;
033: import java.util.IdentityHashMap;
034:
035: import org.jruby.Ruby;
036: import org.jruby.runtime.builtin.IRubyObject;
037: import org.jruby.ast.AndNode;
038: import org.jruby.ast.ArgsNode;
039: import org.jruby.ast.ArgumentNode;
040: import org.jruby.ast.ArrayNode;
041: import org.jruby.ast.BlockNode;
042: import org.jruby.ast.CallNode;
043: import org.jruby.ast.ConstNode;
044: import org.jruby.ast.DefnNode;
045: import org.jruby.ast.NewlineNode;
046: import org.jruby.ast.NotNode;
047: import org.jruby.ast.FixnumNode;
048: import org.jruby.ast.FCallNode;
049: import org.jruby.ast.IfNode;
050: import org.jruby.ast.ListNode;
051: import org.jruby.ast.LocalAsgnNode;
052: import org.jruby.ast.LocalVarNode;
053: import org.jruby.ast.OrNode;
054: import org.jruby.ast.VCallNode;
055: import org.jruby.ast.IArgumentNode;
056: import org.jruby.ast.HashNode;
057: import org.jruby.ast.OptNNode;
058: import org.jruby.ast.Node;
059: import org.jruby.ast.NodeTypes;
060: import org.jruby.ast.RootNode;
061: import org.jruby.ast.StrNode;
062: import org.jruby.ast.UntilNode;
063: import org.jruby.ast.WhileNode;
064: import org.jruby.ast.executable.YARVInstructions;
065: import org.jruby.ast.executable.YARVMachine;
066: import org.jruby.ast.types.ILiteralNode;
067: import org.jruby.ast.types.INameNode;
068: import org.jruby.compiler.Compiler;
069: import org.jruby.compiler.NodeCompiler;
070:
071: /**
072: * @author <a href="mailto:ola.bini@ki.se">Ola Bini</a>
073: */
074: public class StandardYARVCompiler implements NodeCompiler {
075: private YARVMachine.InstructionSequence iseq;
076: private Ruby runtime;
077: private int last_line = -1;
078:
079: private LinkAnchor current_iseq;
080:
081: private String[] locals = new String[0];
082:
083: private static final int COMPILE_OK = 1;
084: private static final int COMPILE_NG = 0;
085:
086: private static abstract class LinkElement {
087: public LinkElement next;
088: public LinkElement prev;
089: }
090:
091: private static class LinkAnchor extends LinkElement {
092: LinkElement last;
093: }
094:
095: private static class Label extends LinkElement {
096: int label_no;
097: int position;
098: int sc_state;
099: int set;
100: int sp;
101: }
102:
103: private static class Insn extends LinkElement {
104: YARVMachine.Instruction i;
105: }
106:
107: private static class EnsureRange {
108: Label begin;
109: Label end;
110: EnsureRange next;
111: }
112:
113: private static void verify_list(String info, LinkAnchor anchor) {
114: int flag = 0;
115: LinkElement list = anchor.next;
116: LinkElement plist = anchor;
117: while (list != null) {
118: if (plist != list.prev) {
119: flag++;
120: }
121: plist = list;
122: list = list.next;
123: }
124:
125: if (anchor.last != plist && anchor.last != null) {
126: flag |= 0x70000;
127: }
128:
129: if (flag != 0) {
130: throw new RuntimeException("list verify error: "
131: + Integer.toString(flag, 16) + " (" + info + ")");
132: }
133: }
134:
135: private int label_no = 0;
136:
137: private Label NEW_LABEL(int l) {
138: Label labelobj = new Label();
139: labelobj.next = null;
140: labelobj.label_no = label_no++;
141: labelobj.sc_state = 0;
142: labelobj.sp = -1;
143: return labelobj;
144: }
145:
146: private static void ADD_LABEL(LinkAnchor anchor, LinkElement elem) {
147: ADD_ELEM(anchor, elem);
148: }
149:
150: private static void ADD_ELEM(LinkAnchor anchor, LinkElement elem) {
151: elem.prev = anchor.last;
152: anchor.last.next = elem;
153: anchor.last = elem;
154: verify_list("add", anchor);
155: }
156:
157: private static void INSERT_ELEM_PREV(LinkElement elem1,
158: LinkElement elem2) {
159: elem2.prev = elem1.prev;
160: elem2.next = elem1;
161: elem1.prev = elem2;
162: if (elem2.prev != null) {
163: elem2.prev.next = elem2;
164: }
165: }
166:
167: private static void REPLACE_ELEM(LinkElement elem1,
168: LinkElement elem2) {
169: elem2.prev = elem1.prev;
170: elem2.next = elem1.next;
171: if (elem1.prev != null) {
172: elem1.prev.next = elem2;
173: }
174: if (elem1.next != null) {
175: elem1.next.prev = elem2;
176: }
177: }
178:
179: private static void REMOVE_ELEM(LinkElement elem) {
180: elem.prev.next = elem.next;
181: if (elem.next != null) {
182: elem.next.prev = elem.prev;
183: }
184: }
185:
186: private static LinkElement FIRST_ELEMENT(LinkAnchor anchor) {
187: return anchor.next;
188: }
189:
190: private static LinkElement POP_ELEMENT(LinkAnchor anchor) {
191: LinkElement elem = anchor.last;
192: anchor.last = anchor.last.prev;
193: anchor.last.next = null;
194: verify_list("pop", anchor);
195: return elem;
196: }
197:
198: private static LinkElement SHIFT_ELEMENT(LinkAnchor anchor) {
199: LinkElement elem = anchor.next;
200: if (null != elem) {
201: anchor.next = elem.next;
202: }
203: return elem;
204: }
205:
206: private static int LIST_SIZE(LinkAnchor anchor) {
207: LinkElement elem = anchor.next;
208: int size = 0;
209: while (elem != null) {
210: size++;
211: elem = elem.next;
212: }
213: return size;
214: }
215:
216: private static boolean LIST_SIZE_ZERO(LinkAnchor anchor) {
217: return anchor.next == null;
218: }
219:
220: private static void APPEND_LIST(LinkAnchor anc1, LinkAnchor anc2) {
221: if (anc2.next != null) {
222: anc1.last.next = anc2.next;
223: anc2.next.prev = anc1.last;
224: anc1.last = anc2.last;
225: }
226: verify_list("append", anc1);
227: }
228:
229: private static void INSERT_LIST(LinkAnchor anc1, LinkAnchor anc2) {
230: if (anc2.next != null) {
231: LinkElement first = anc1.next;
232: anc1.next = anc2.next;
233: anc1.next.prev = anc1;
234: anc2.last.next = first;
235: if (first != null) {
236: first.prev = anc2.last;
237: } else {
238: anc1.last = anc2.last;
239: }
240: }
241: verify_list("append", anc1);
242: }
243:
244: private static void ADD_SEQ(LinkAnchor seq1, LinkAnchor seq2) {
245: APPEND_LIST(seq1, seq2);
246: }
247:
248: private int debug_compile(String msg, int v) {
249: debugs(msg);
250: return v;
251: }
252:
253: private int COMPILE(LinkAnchor anchor, String desc, Node node) {
254: return debug_compile("== " + desc, iseq_compile_each(anchor,
255: node, false));
256: }
257:
258: private int COMPILE(LinkAnchor anchor, String desc, Node node,
259: boolean poped) {
260: return debug_compile("== " + desc, iseq_compile_each(anchor,
261: node, poped));
262: }
263:
264: private int COMPILE_POPED(LinkAnchor anchor, String desc, Node node) {
265: return debug_compile("== " + desc, iseq_compile_each(anchor,
266: node, true));
267: }
268:
269: private LinkAnchor DECL_ANCHOR() {
270: LinkAnchor l = new LinkAnchor();
271: l.last = l;
272: return l;
273: }
274:
275: public StandardYARVCompiler(Ruby runtime) {
276: this .runtime = runtime;
277: }
278:
279: private void debugs(String s) {
280: System.err.println(s);
281: }
282:
283: public void compile(Node node) {
284: iseq_compile(null, node);
285: }
286:
287: public void compile(Node node, Compiler context) {
288: compile(node);
289: }
290:
291: public void iseq_compile(IRubyObject self, Node narg) {
292: LinkAnchor list_anchor = DECL_ANCHOR();
293: Node node = narg;
294: debugs("[compile step 1 (traverse each node)]");
295: COMPILE(list_anchor, "top level node", node);
296: ADD_INSN(list_anchor, last_line, YARVInstructions.LEAVE);
297: current_iseq = list_anchor;
298: }
299:
300: private int nd_line(Node node) {
301: if (node.getPosition() != null) {
302: return node.getPosition().getEndLine();
303: }
304: return last_line;
305: }
306:
307: private String nd_file(Node node) {
308: if (node.getPosition() != null) {
309: return node.getPosition().getFile();
310: }
311: return null;
312: }
313:
314: private int iseq_compile_each(LinkAnchor ret, Node node,
315: boolean poped) {
316: if (node == null) {
317: if (!poped) {
318: debugs("NODE_NIL(implicit)");
319: ADD_INSN(ret, 0, YARVInstructions.PUTNIL);
320: return COMPILE_OK;
321: }
322: return COMPILE_OK;
323: }
324: last_line = nd_line(node);
325:
326: LinkAnchor recv = null;
327: LinkAnchor args = null;
328:
329: compileLoop: while (true) {
330: switch (node.nodeId) {
331: case NodeTypes.BLOCKNODE:
332: List l = ((BlockNode) node).childNodes();
333: int sz = l.size();
334: for (int i = 0; i < sz; i++) {
335: boolean p = !(i + 1 == sz && !poped);
336: COMPILE(ret, "BLOCK body", (Node) l.get(i), p);
337: }
338: break compileLoop;
339: case NodeTypes.NEWLINENODE:
340: node = ((NewlineNode) node).getNextNode();
341: continue compileLoop;
342: case NodeTypes.ROOTNODE:
343: // getAllNamesInScope now gets all names in scope that have been seen at the current point
344: // of execution. This may or may not work in this case....?
345: locals = ((RootNode) node).getStaticScope()
346: .getAllNamesInScope(
347: ((RootNode) node).getScope());
348: node = ((RootNode) node).getBodyNode();
349: continue compileLoop;
350: case NodeTypes.DEFNNODE:
351: StandardYARVCompiler c = new StandardYARVCompiler(
352: runtime);
353: c.compile(((DefnNode) node).getBodyNode());
354: YARVMachine.InstructionSequence iseqval = c
355: .getInstructionSequence(((DefnNode) node)
356: .getName(), nd_file(node), "method");
357: List argNames = new ArrayList();
358: ListNode argsNode = ((DefnNode) node).getArgsNode()
359: .getArgs();
360: for (int i = 0; i < argsNode.size(); i++) {
361: ArgumentNode argumentNode = (ArgumentNode) argsNode
362: .get(i);
363:
364: argNames.add(argumentNode.getName());
365: }
366: iseqval.args_argc = argNames.size();
367: String[] l1 = iseqval.locals;
368: String[] l2 = new String[l1.length + argNames.size()];
369: System.arraycopy(l1, 0, l2, argNames.size(), l1.length);
370: for (int i = 0; i < argNames.size(); i++) {
371: l2[i] = (String) argNames.get(i);
372: }
373: iseqval.locals = l2;
374: ADD_INSN(ret, nd_line(node), YARVInstructions.PUTNIL);
375: ADD_INSN3(ret, nd_line(node),
376: YARVInstructions.DEFINEMETHOD,
377: ((DefnNode) node).getName(), iseqval, 0);
378: if (!poped) {
379: ADD_INSN(ret, nd_line(node),
380: YARVInstructions.PUTNIL);
381: }
382: break compileLoop;
383: case NodeTypes.STRNODE:
384: if (!poped) {
385: ADD_INSN1(ret, nd_line(node),
386: YARVInstructions.PUTSTRING,
387: ((StrNode) node).getValue().toString());
388: }
389: break compileLoop;
390: case NodeTypes.CONSTNODE:
391: // Check for inline const cache here
392: ADD_INSN(ret, nd_line(node), YARVInstructions.PUTNIL);
393: ADD_INSN1(ret, nd_line(node),
394: YARVInstructions.GETCONSTANT,
395: ((ConstNode) node).getName());
396: if (poped) {
397: ADD_INSN(ret, nd_line(node), YARVInstructions.POP);
398: }
399: break compileLoop;
400: case NodeTypes.LOCALASGNNODE:
401: int idx = ((LocalAsgnNode) node).getIndex() - 2;
402: debugs("lvar: " + idx);
403: COMPILE(ret, "lvalue", ((LocalAsgnNode) node)
404: .getValueNode());
405: if (!poped) {
406: ADD_INSN(ret, nd_line(node), YARVInstructions.DUP);
407: }
408: ADD_INSN1(ret, nd_line(node),
409: YARVInstructions.SETLOCAL, idx);
410: break compileLoop;
411: case NodeTypes.LOCALVARNODE:
412: if (!poped) {
413: int idx2 = ((LocalVarNode) node).getIndex() - 2;
414: debugs("idx: " + idx2);
415: ADD_INSN1(ret, nd_line(node),
416: YARVInstructions.GETLOCAL, idx2);
417: }
418: break compileLoop;
419: case NodeTypes.IFNODE: {
420: LinkAnchor cond_seq = DECL_ANCHOR();
421: LinkAnchor then_seq = DECL_ANCHOR();
422: LinkAnchor else_seq = DECL_ANCHOR();
423:
424: Label then_label = NEW_LABEL(nd_line(node));
425: Label else_label = NEW_LABEL(nd_line(node));
426: Label end_label = NEW_LABEL(nd_line(node));
427:
428: compile_branch_condition(cond_seq, ((IfNode) node)
429: .getCondition(), then_label, else_label);
430:
431: COMPILE(then_seq, "then",
432: ((IfNode) node).getThenBody(), poped);
433: COMPILE(else_seq, "else",
434: ((IfNode) node).getElseBody(), poped);
435:
436: ADD_SEQ(ret, cond_seq);
437:
438: ADD_LABEL(ret, then_label);
439: ADD_SEQ(ret, then_seq);
440:
441: ADD_INSNL(ret, nd_line(node), YARVInstructions.JUMP,
442: end_label);
443:
444: ADD_LABEL(ret, else_label);
445: ADD_SEQ(ret, else_seq);
446:
447: ADD_LABEL(ret, end_label);
448: break compileLoop;
449: }
450: case NodeTypes.CALLNODE:
451: case NodeTypes.FCALLNODE:
452: case NodeTypes.VCALLNODE:
453: recv = DECL_ANCHOR();
454: args = DECL_ANCHOR();
455: if (node instanceof CallNode) {
456: COMPILE(recv, "recv", ((CallNode) node)
457: .getReceiverNode());
458: } else {
459: ADD_CALL_RECEIVER(recv, nd_line(node));
460: }
461: int argc = 0;
462: int flags = 0;
463: if (!(node instanceof VCallNode)) {
464: int[] argc_flags = setup_arg(args,
465: (IArgumentNode) node);
466: argc = argc_flags[0];
467: flags = argc_flags[1];
468: } else {
469: argc = 0;
470: }
471:
472: ADD_SEQ(ret, recv);
473: ADD_SEQ(ret, args);
474:
475: switch (node.nodeId) {
476: case NodeTypes.VCALLNODE:
477: flags |= YARVInstructions.VCALL_FLAG;
478: /* VCALL is funcall, so fall through */
479: case NodeTypes.FCALLNODE:
480: flags |= YARVInstructions.FCALL_FLAG;
481: }
482:
483: ADD_SEND_R(ret, nd_line(node), ((INameNode) node)
484: .getName(), argc, null, flags);
485: if (poped) {
486: ADD_INSN(ret, nd_line(node), YARVInstructions.POP);
487: }
488: break compileLoop;
489: case NodeTypes.ARRAYNODE:
490: compile_array(ret, node, true);
491: if (poped) {
492: ADD_INSN(ret, nd_line(node), YARVInstructions.POP);
493: }
494: break compileLoop;
495: case NodeTypes.ZARRAYNODE:
496: if (!poped) {
497: ADD_INSN1(ret, nd_line(node),
498: YARVInstructions.NEWARRAY, 0);
499: }
500: break compileLoop;
501: case NodeTypes.HASHNODE:
502: LinkAnchor list = DECL_ANCHOR();
503: long size = 0;
504: Node lnode = ((HashNode) node).getListNode();
505: if (lnode.childNodes().size() > 0) {
506: compile_array(list, lnode, false);
507: size = ((Insn) POP_ELEMENT(list)).i.l_op0;
508: ADD_SEQ(ret, list);
509: }
510:
511: ADD_INSN1(ret, nd_line(node), YARVInstructions.NEWHASH,
512: size);
513:
514: if (poped) {
515: ADD_INSN(ret, nd_line(node), YARVInstructions.POP);
516: }
517: break compileLoop;
518: case NodeTypes.FIXNUMNODE:
519: FixnumNode iVisited = (FixnumNode) node;
520: if (!poped) {
521: ADD_INSN1(ret, nd_line(node),
522: YARVInstructions.PUTOBJECT, iVisited
523: .getFixnum(runtime));
524: }
525: break compileLoop;
526: case NodeTypes.OPTNNODE:
527: case NodeTypes.WHILENODE:
528: case NodeTypes.UNTILNODE: {
529: Label next_label = NEW_LABEL(nd_line(node)); /* next */
530: Label redo_label = NEW_LABEL(nd_line(node)); /* redo */
531: Label break_label = NEW_LABEL(nd_line(node)); /* break */
532: Label end_label = NEW_LABEL(nd_line(node));
533:
534: if (node instanceof OptNNode) {
535: ADD_INSNL(ret, nd_line(node),
536: YARVInstructions.JUMP, next_label);
537: }
538:
539: ADD_LABEL(ret, redo_label);
540:
541: Node body = null;
542: if (node instanceof WhileNode) {
543: body = ((WhileNode) node).getBodyNode();
544: } else if (node instanceof UntilNode) {
545: body = ((UntilNode) node).getBodyNode();
546: } else if (node instanceof OptNNode) {
547: body = ((OptNNode) node).getBodyNode();
548: }
549: COMPILE_POPED(ret, "while body", body);
550: ADD_LABEL(ret, next_label); /* next */
551:
552: if (node instanceof WhileNode) {
553: compile_branch_condition(ret, ((WhileNode) node)
554: .getConditionNode(), redo_label, end_label);
555: } else if (node instanceof UntilNode) {
556: /* untile */
557: compile_branch_condition(ret, ((UntilNode) node)
558: .getConditionNode(), end_label, redo_label);
559: } else {
560: ADD_CALL_RECEIVER(ret, nd_line(node));
561: //TODO: ADD_CALL(ret, nd_line(node), ID2SYM(idGets), INT2FIX(0));
562: ADD_INSNL(ret, nd_line(node),
563: YARVInstructions.BRANCHIF, redo_label);
564: /* opt_n */
565: }
566:
567: ADD_LABEL(ret, end_label);
568: ADD_INSN(ret, nd_line(node), YARVInstructions.PUTNIL);
569: ADD_LABEL(ret, break_label); /* braek */
570: if (poped) {
571: ADD_INSN(ret, nd_line(node), YARVInstructions.POP);
572: }
573: break compileLoop;
574: }
575:
576: default:
577: debugs(" ... doesn't handle node: " + node);
578: break compileLoop;
579: }
580: }
581:
582: return COMPILE_OK;
583: }
584:
585: private int compile_branch_condition(LinkAnchor ret, Node cond,
586: Label then_label, Label else_label) {
587: switch (cond.nodeId) {
588: case NodeTypes.NOTNODE:
589: compile_branch_condition(ret, ((NotNode) cond)
590: .getConditionNode(), else_label, then_label);
591: break;
592: case NodeTypes.ANDNODE: {
593: Label label = NEW_LABEL(nd_line(cond));
594: compile_branch_condition(ret, ((AndNode) cond)
595: .getFirstNode(), label, else_label);
596: ADD_LABEL(ret, label);
597: compile_branch_condition(ret, ((AndNode) cond)
598: .getSecondNode(), then_label, else_label);
599: break;
600: }
601: case NodeTypes.ORNODE: {
602: Label label = NEW_LABEL(nd_line(cond));
603: compile_branch_condition(ret, ((OrNode) cond)
604: .getFirstNode(), then_label, label);
605: ADD_LABEL(ret, label);
606: compile_branch_condition(ret, ((OrNode) cond)
607: .getSecondNode(), then_label, else_label);
608: break;
609: }
610: case NodeTypes.TRUENODE:
611: case NodeTypes.STRNODE:
612: ADD_INSNL(ret, nd_line(cond), YARVInstructions.JUMP,
613: then_label);
614: break;
615: case NodeTypes.FALSENODE:
616: case NodeTypes.NILNODE:
617: ADD_INSNL(ret, nd_line(cond), YARVInstructions.JUMP,
618: else_label);
619: break;
620: default:
621: COMPILE(ret, "branch condition", cond);
622: ADD_INSNL(ret, nd_line(cond),
623: YARVInstructions.BRANCHUNLESS, else_label);
624: ADD_INSNL(ret, nd_line(cond), YARVInstructions.JUMP,
625: then_label);
626: break;
627: }
628:
629: return COMPILE_OK;
630: }
631:
632: private int compile_array(LinkAnchor ret, Node node_root,
633: boolean opt_p) {
634: Node node = node_root;
635: int len = ((ArrayNode) node).size();
636: int line = nd_line(node);
637: int i = 0;
638: LinkAnchor anchor = DECL_ANCHOR();
639: List c = node.childNodes();
640: for (Iterator iter = c.iterator(); iter.hasNext();) {
641: node = (Node) iter.next();
642: if (opt_p && !(node instanceof ILiteralNode)) {
643: opt_p = false;
644: }
645: COMPILE(anchor, "array element", node);
646: }
647:
648: if (opt_p) {
649: List l = new ArrayList();
650: for (Iterator iter = c.iterator(); iter.hasNext();) {
651: node = (Node) iter.next();
652: switch (node.nodeId) {
653: case NodeTypes.FIXNUMNODE:
654: l.add(((FixnumNode) node).getFixnum(runtime));
655: break;
656: default:
657: debugs(" ... doesn't handle array literal node: "
658: + node);
659: break;
660: }
661: }
662: ADD_INSN1(ret, nd_line(node_root),
663: YARVInstructions.DUPARRAY, runtime.newArray(l));
664: } else {
665: ADD_INSN1(anchor, line, YARVInstructions.NEWARRAY, len);
666: APPEND_LIST(ret, anchor);
667: }
668:
669: return len;
670: }
671:
672: private int[] setup_arg(LinkAnchor args, IArgumentNode node) {
673: int[] n = new int[] { 0, 0 };
674: Node argn = node.getArgsNode();
675: LinkAnchor arg_block = DECL_ANCHOR();
676: LinkAnchor args_push = DECL_ANCHOR();
677:
678: if (argn != null) {
679: switch (argn.nodeId) {
680: case NodeTypes.SPLATNODE:
681: break;
682: case NodeTypes.ARGSCATNODE:
683: break;
684: case NodeTypes.ARGSPUSHNODE:
685: break;
686: default:
687: n[0] = compile_array(args, argn, false);
688: POP_ELEMENT(args);
689: break;
690: }
691: }
692:
693: if (!LIST_SIZE_ZERO(args_push)) {
694: ADD_SEQ(args, args_push);
695: }
696:
697: return n;
698: }
699:
700: private Insn new_insn(YARVMachine.Instruction i) {
701: Insn n = new Insn();
702: n.i = i;
703: n.next = null;
704: return n;
705: }
706:
707: private void ADD_CALL_RECEIVER(LinkAnchor seq, int line) {
708: ADD_INSN(seq, line, YARVInstructions.PUTNIL);
709: }
710:
711: private void ADD_INSN(LinkAnchor seq, int line, int insn) {
712: YARVMachine.Instruction i = new YARVMachine.Instruction(insn);
713: i.line_no = line;
714: debugs("ADD_INSN(" + line + ", " + YARVInstructions.name(insn)
715: + ")");
716: ADD_ELEM(seq, new_insn(i));
717: }
718:
719: private void ADD_SEND_R(LinkAnchor seq, int line, String name,
720: int argc, Object block, int flags) {
721: YARVMachine.Instruction i = new YARVMachine.Instruction(
722: YARVInstructions.SEND);
723: i.line_no = line;
724: i.s_op0 = name;
725: i.i_op1 = argc;
726: i.i_op3 = flags;
727: debugs("ADD_SEND_R(" + line + ", "
728: + YARVInstructions.name(YARVInstructions.SEND) + ", "
729: + name + ", " + argc + ", " + flags + ")");
730: ADD_ELEM(seq, new_insn(i));
731: }
732:
733: private void ADD_INSN1(LinkAnchor seq, int line, int insn,
734: IRubyObject obj) {
735: YARVMachine.Instruction i = new YARVMachine.Instruction(insn);
736: i.line_no = line;
737: i.o_op0 = obj;
738: debugs("ADD_INSN1(" + line + ", " + YARVInstructions.name(insn)
739: + ", " + obj + ")");
740: ADD_ELEM(seq, new_insn(i));
741: }
742:
743: private void ADD_INSN1(LinkAnchor seq, int line, int insn, long op) {
744: YARVMachine.Instruction i = new YARVMachine.Instruction(insn);
745: i.line_no = line;
746: i.l_op0 = op;
747: debugs("ADD_INSN1(" + line + ", " + YARVInstructions.name(insn)
748: + ", " + op + ")");
749: ADD_ELEM(seq, new_insn(i));
750: }
751:
752: private void ADD_INSNL(LinkAnchor seq, int line, int insn, Label l) {
753: YARVMachine.Instruction i = new YARVMachine.Instruction(insn);
754: i.line_no = line;
755: i._tmp = l;
756: debugs("ADD_INSNL(" + line + ", " + YARVInstructions.name(insn)
757: + ", " + l + ")");
758: ADD_ELEM(seq, new_insn(i));
759: }
760:
761: private void ADD_INSN1(LinkAnchor seq, int line, int insn,
762: String obj) {
763: YARVMachine.Instruction i = new YARVMachine.Instruction(insn);
764: i.line_no = line;
765: i.s_op0 = obj;
766: debugs("ADD_INSN1(" + line + ", " + YARVInstructions.name(insn)
767: + ", " + obj + ")");
768: ADD_ELEM(seq, new_insn(i));
769: }
770:
771: private void ADD_INSN3(LinkAnchor seq, int line, int insn,
772: String name, YARVMachine.InstructionSequence iseq, long n) {
773: YARVMachine.Instruction i = new YARVMachine.Instruction(insn);
774: i.line_no = line;
775: i.s_op0 = name;
776: i.iseq_op = iseq;
777: i.l_op0 = n;
778: debugs("ADD_INSN3(" + line + ", " + YARVInstructions.name(insn)
779: + ", " + name + ", " + iseq + ", " + n + ")");
780: ADD_ELEM(seq, new_insn(i));
781: }
782:
783: public YARVMachine.InstructionSequence getInstructionSequence(
784: String name, String filename, String level) {
785: iseq = new YARVMachine.InstructionSequence(runtime, name,
786: filename, level);
787: List l = new ArrayList();
788: LinkElement elm = current_iseq;
789: Map jumps = new IdentityHashMap();
790: Map labels = new IdentityHashMap();
791: int real = 0;
792: while (elm != null) {
793: if (elm instanceof Insn) {
794: Insn i = (Insn) elm;
795: if (isJump(i.i.bytecode)) {
796: jumps.put(i, i.i._tmp);
797: }
798: l.add(i.i);
799: real++;
800: } else if (elm instanceof Label) {
801: labels.put(elm, new Integer(real + 1));
802: }
803: elm = elm.next;
804: }
805: for (Iterator iter = jumps.keySet().iterator(); iter.hasNext();) {
806: Insn k = (Insn) iter.next();
807: k.i.l_op0 = ((Integer) labels.get(jumps.get(k))).intValue() - 1;
808: k.i._tmp = null;
809: }
810:
811: debugs("instructions: " + l);
812: iseq.body = (YARVMachine.Instruction[]) l
813: .toArray(new YARVMachine.Instruction[l.size()]);
814: iseq.locals = locals;
815: return iseq;
816: }
817:
818: private boolean isJump(int i) {
819: return i == YARVInstructions.JUMP
820: || i == YARVInstructions.BRANCHIF
821: || i == YARVInstructions.BRANCHUNLESS
822: || i == YARVInstructions.GETINLINECACHE
823: || i == YARVInstructions.SETINLINECACHE;
824: }
825: }// StandardYARVCompiler
|