1 28 package org.jruby.internal.runtime.methods; 29 30 import java.util.ArrayList ; 31 import org.jruby.Ruby; 32 import org.jruby.RubyArray; 33 import org.jruby.RubyModule; 34 import org.jruby.exceptions.JumpException; 35 import org.jruby.lexer.yacc.ISourcePosition; 36 import org.jruby.parser.StaticScope; 37 import org.jruby.runtime.Arity; 38 import org.jruby.runtime.Block; 39 import org.jruby.runtime.DynamicScope; 40 import org.jruby.runtime.ThreadContext; 41 import org.jruby.runtime.Visibility; 42 import org.jruby.runtime.builtin.IRubyObject; 43 import org.jruby.util.collections.SinglyLinkedList; 44 import org.jruby.ast.executable.YARVMachine; 45 import org.jruby.ast.executable.ISeqPosition; 46 47 51 public class YARVMethod extends DynamicMethod { 52 private SinglyLinkedList cref; 53 private YARVMachine.InstructionSequence iseq; 54 private StaticScope staticScope; 55 private Arity arity; 56 57 public YARVMethod(RubyModule implementationClass, YARVMachine.InstructionSequence iseq, StaticScope staticScope, Visibility visibility, SinglyLinkedList cref) { 58 super(implementationClass, visibility); 59 this.staticScope = staticScope; 60 this.iseq = iseq; 61 this.cref = cref; 62 63 boolean opts = iseq.args_arg_opts > 0 || iseq.args_rest > 0; 64 boolean req = iseq.args_argc > 0; 65 if(!req && !opts) { 66 this.arity = Arity.noArguments(); 67 } else if(req && !opts) { 68 this.arity = Arity.fixed(iseq.args_argc); 69 } else if(opts && !req) { 70 this.arity = Arity.optional(); 71 } else { 72 this.arity = Arity.required(iseq.args_argc); 73 } 74 } 75 76 public void preMethod(ThreadContext context, RubyModule clazz, IRubyObject self, String name, 77 IRubyObject[] args, boolean noSuper, Block block) { 78 context.preDefMethodInternalCall(clazz, name, self, args, block, noSuper, cref, staticScope); 79 } 80 81 public void postMethod(ThreadContext context) { 82 context.postDefMethodInternalCall(); 83 } 84 85 public IRubyObject internalCall(ThreadContext context, RubyModule klazz, IRubyObject self, String name, IRubyObject[] args, boolean noSuper, Block block) { 86 assert args != null; 87 88 Ruby runtime = context.getRuntime(); 89 90 try { 91 prepareArguments(context, runtime, args); 92 getArity().checkArity(runtime, args); 93 94 traceCall(context, runtime, self, name); 95 96 DynamicScope sc = new DynamicScope(staticScope,null); 97 for(int i = 0; i<args.length; i++) { 98 sc.setValue(i,args[i],0); 99 } 100 101 return YARVMachine.INSTANCE.exec(context, self, sc, iseq.body); 102 } catch (JumpException je) { 103 if (je.getJumpType() == JumpException.JumpType.ReturnJump && je.getTarget() == this) { 104 return (IRubyObject) je.getValue(); 105 } 106 107 throw je; 108 } finally { 109 traceReturn(context, runtime, self, name); 110 } 111 } 112 113 private void prepareArguments(ThreadContext context, Ruby runtime, IRubyObject[] args) { 114 context.setPosition(new ISeqPosition(iseq)); 115 116 int expectedArgsCount = iseq.args_argc; 117 int restArg = iseq.args_rest; 118 boolean hasOptArgs = iseq.args_arg_opts > 0; 119 120 if (expectedArgsCount > args.length) { 121 throw runtime.newArgumentError("Wrong # of arguments(" + args.length + " for " + expectedArgsCount + ")"); 122 } 123 124 if (hasOptArgs || restArg != -1) { 126 args = prepareOptOrRestArgs(context, runtime, args, expectedArgsCount, restArg, hasOptArgs); 127 } 128 129 context.setFrameArgs(args); 130 } 131 132 private IRubyObject[] prepareOptOrRestArgs(ThreadContext context, Ruby runtime, IRubyObject[] args, int expectedArgsCount, int restArg, boolean hasOptArgs) { 133 if (restArg == 0 && hasOptArgs) { 134 int opt = expectedArgsCount + iseq.args_arg_opts; 135 136 if (opt < args.length) { 137 throw runtime.newArgumentError("wrong # of arguments(" + args.length + " for " + opt + ")"); 138 } 139 } 140 141 int count = expectedArgsCount + iseq.args_arg_opts + iseq.args_rest; 142 143 ArrayList allArgs = new ArrayList (); 144 145 for (int i = 0; i < count && i < args.length; i++) { 147 allArgs.add(args[i]); 148 } 149 150 if (restArg != 0) { 151 for (int i = expectedArgsCount; i < args.length; i++) { 152 allArgs.add(args[i]); 153 } 154 155 if (restArg >= 0) { 157 RubyArray array = runtime.newArray(args.length - expectedArgsCount); 158 for (int i = expectedArgsCount; i < args.length; i++) { 159 array.append(args[i]); 160 } 161 162 context.getCurrentScope().setValue(restArg, array, 0); 163 } 164 } 165 166 args = (IRubyObject[])allArgs.toArray(new IRubyObject[allArgs.size()]); 167 return args; 168 } 169 170 private void traceReturn(ThreadContext context, Ruby runtime, IRubyObject receiver, String name) { 171 if (runtime.getTraceFunction() == null) { 172 return; 173 } 174 175 ISourcePosition position = context.getPreviousFramePosition(); 176 runtime.callTraceFunction(context, "return", position, receiver, name, getImplementationClass()); 177 } 178 179 private void traceCall(ThreadContext context, Ruby runtime, IRubyObject receiver, String name) { 180 if (runtime.getTraceFunction() == null) { 181 return; 182 } 183 184 ISourcePosition position = context.getPosition(); 185 186 runtime.callTraceFunction(context, "call", position, receiver, name, getImplementationClass()); 187 } 188 189 public Arity getArity() { 190 return this.arity; 191 } 192 193 public DynamicMethod dup() { 194 return new YARVMethod(getImplementationClass(), iseq, staticScope, getVisibility(), cref); 195 } 196 } | Popular Tags |