1 28 package org.jruby.ast.executable; 29 30 import java.io.Reader ; 31 import java.io.IOException ; 32 33 import java.util.Iterator ; 34 import java.util.List ; 35 import java.util.Map ; 36 import java.util.HashMap ; 37 import java.util.IdentityHashMap ; 38 39 import org.jruby.Ruby; 40 import org.jruby.RubyFile; 41 import org.jruby.RubyArray; 42 import org.jruby.RubyNumeric; 43 import org.jruby.RubyString; 44 import org.jruby.RubySymbol; 45 import org.jruby.parser.LocalStaticScope; 46 import org.jruby.parser.StaticScope; 47 import org.jruby.runtime.DynamicScope; 48 import org.jruby.runtime.ThreadContext; 49 import org.jruby.runtime.builtin.IRubyObject; 50 51 54 public class YARVCompiledRunner { 55 private Ruby runtime; 56 private YARVMachine ym = YARVMachine.INSTANCE; 57 58 private YARVMachine.InstructionSequence iseq; 59 60 private Map jumps = new IdentityHashMap (); 61 private Map labels = new HashMap (); 62 63 public YARVCompiledRunner(Ruby runtime, Reader reader, String filename) { 64 this.runtime = runtime; 65 char[] first = new char[4]; 66 try { 67 reader.read(first); 68 if(first[0] != 'R' || first[1] != 'B' || first[2] != 'C' || first[3] != 'M') { 69 throw new RuntimeException ("File is not a compiled YARV file"); 70 } 71 RubyFile f = new RubyFile(runtime,filename,reader); 72 IRubyObject arr = runtime.getModule("Marshal").callMethod(runtime.getCurrentContext(),"load",f); 73 iseq = transformIntoSequence(arr); 74 } catch(IOException e) { 75 throw new RuntimeException ("Couldn't read from source",e); 76 } 77 } 78 79 public YARVCompiledRunner(Ruby runtime, YARVMachine.InstructionSequence iseq) { 80 this.runtime = runtime; 81 this.iseq = iseq; 82 } 83 84 public IRubyObject run() { 85 ThreadContext context = runtime.getCurrentContext(); 86 StaticScope scope = new LocalStaticScope(null); 87 scope.setVariables(iseq.locals); 88 context.setPosition(new ISeqPosition(iseq)); 89 return ym.exec(context, runtime.getObject(), new DynamicScope(scope,null), iseq.body); 90 } 91 92 private YARVMachine.InstructionSequence transformIntoSequence(IRubyObject arr) { 93 if(!(arr instanceof RubyArray)) { 94 throw new RuntimeException ("Error when reading compiled YARV file"); 95 } 96 labels.clear(); 97 jumps.clear(); 98 99 YARVMachine.InstructionSequence seq = new YARVMachine.InstructionSequence(runtime,null,null,null); 100 Iterator internal = (((RubyArray)arr).getList()).iterator(); 101 seq.magic = internal.next().toString(); 102 seq.major = RubyNumeric.fix2int((IRubyObject)internal.next()); 103 seq.minor = RubyNumeric.fix2int((IRubyObject)internal.next()); 104 seq.format_type = RubyNumeric.fix2int((IRubyObject)internal.next()); 105 IRubyObject misc = (IRubyObject)internal.next(); 106 if(misc.isNil()) { 107 seq.misc = null; 108 } else { 109 seq.misc = misc; 110 } 111 seq.name = internal.next().toString(); 112 seq.filename = internal.next().toString(); 113 seq.line = new Object [0]; internal.next(); 114 seq.type = internal.next().toString(); 115 seq.locals = toStringArray((IRubyObject)internal.next()); 116 IRubyObject argo = (IRubyObject)internal.next(); 117 if(argo instanceof RubyArray) { 118 List arglist = ((RubyArray)argo).getList(); 119 seq.args_argc = RubyNumeric.fix2int((IRubyObject)arglist.get(0)); 120 seq.args_arg_opts = RubyNumeric.fix2int((IRubyObject)arglist.get(1)); 121 seq.args_opt_labels = toStringArray((IRubyObject)arglist.get(2)); 122 seq.args_rest = RubyNumeric.fix2int((IRubyObject)arglist.get(3)); 123 seq.args_block = RubyNumeric.fix2int((IRubyObject)arglist.get(4)); 124 } else { 125 seq.args_argc = RubyNumeric.fix2int(argo); 126 } 127 128 seq.exception = getExceptionInformation((IRubyObject)internal.next()); 129 130 List bodyl = ((RubyArray)internal.next()).getList(); 131 YARVMachine.Instruction[] body = new YARVMachine.Instruction[bodyl.size()]; 132 int real=0; 133 int i=0; 134 for(Iterator iter = bodyl.iterator();iter.hasNext();i++) { 135 IRubyObject is = (IRubyObject)iter.next(); 136 if(is instanceof RubyArray) { 137 body[real] = intoInstruction((RubyArray)is,real,seq); 138 real++; 139 } else if(is instanceof RubySymbol) { 140 labels.put(is.toString(), new Integer (real+1)); 141 } 142 } 143 YARVMachine.Instruction[] nbody = new YARVMachine.Instruction[real]; 144 System.arraycopy(body,0,nbody,0,real); 145 seq.body = nbody; 146 147 for(Iterator iter = jumps.keySet().iterator();iter.hasNext();) { 148 YARVMachine.Instruction k = (YARVMachine.Instruction)iter.next(); 149 k.l_op0 = ((Integer )labels.get(jumps.get(k))).intValue() - 1; 150 } 151 152 return seq; 153 } 154 155 private String [] toStringArray(IRubyObject obj) { 156 if(obj.isNil()) { 157 return new String [0]; 158 } else { 159 List l = ((RubyArray)obj).getList(); 160 String [] s = new String [l.size()]; 161 int i=0; 162 for(Iterator iter = l.iterator();iter.hasNext();i++) { 163 s[i] = iter.next().toString(); 164 } 165 return s; 166 } 167 } 168 169 private YARVMachine.Instruction intoInstruction(RubyArray obj, int n, YARVMachine.InstructionSequence iseq) { 170 List internal = obj.getList(); 171 String name = internal.get(0).toString(); 172 int instruction = YARVMachine.instruction(name); 173 YARVMachine.Instruction i = new YARVMachine.Instruction(instruction); 174 if(internal.size() > 1) { 175 IRubyObject first = (IRubyObject)internal.get(1); 176 if(instruction == YARVInstructions.GETLOCAL || instruction == YARVInstructions.SETLOCAL) { 177 i.l_op0 = (iseq.locals.length + 1) - RubyNumeric.fix2long(first); 178 } else if(instruction == YARVInstructions.PUTOBJECT || instruction == YARVInstructions.OPT_REGEXPMATCH1 || instruction == YARVInstructions.GETINLINECACHE) { 179 i.o_op0 = first; 180 } else if(first instanceof RubyString || first instanceof RubySymbol ) { 181 i.s_op0 = first.toString(); 182 } else if(first instanceof RubyNumeric) { 183 i.l_op0 = RubyNumeric.fix2long(first); 184 } 185 if(instruction == YARVInstructions.SEND) { 186 i.i_op1 = RubyNumeric.fix2int((IRubyObject)internal.get(2)); 187 i.i_op3 = RubyNumeric.fix2int((IRubyObject)internal.get(4)); 188 } 189 if(instruction == YARVInstructions.DEFINEMETHOD) { 190 i.iseq_op = transformIntoSequence((IRubyObject)internal.get(2)); 191 } 192 if(isJump(instruction)) { 193 i.index = n; 194 jumps.put(i, internal.get(jumpIndex(instruction)).toString()); 195 } 196 } 197 return i; 198 } 199 200 private boolean isJump(int i) { 201 return i == YARVInstructions.JUMP || i == YARVInstructions.BRANCHIF || i == YARVInstructions.BRANCHUNLESS || 202 i == YARVInstructions.GETINLINECACHE || i == YARVInstructions.SETINLINECACHE; 203 } 204 205 private int jumpIndex(int i) { 206 if(i == YARVInstructions.GETINLINECACHE) { 207 return 2; 208 } else { 209 return 1; 210 } 211 } 212 213 private Object [] getExceptionInformation(IRubyObject obj) { 214 return new Object [0]; 216 } 217 } | Popular Tags |