/** * For Type.LAMBDA, ensures that the args have the correct arity. * * <p>For others, transforms the given arguments appropriately for the given arity (i.e. trimming * to one arg for fixed arity of one, etc.) */ public static IRubyObject[] prepareArgs( ThreadContext context, Block.Type type, BlockBody blockBody, IRubyObject[] args) { Signature signature = blockBody.getSignature(); if (args == null) return IRubyObject.NULL_ARRAY; if (type == Block.Type.LAMBDA) { signature.checkArity(context.runtime, args); return args; } boolean isFixed = signature.isFixed(); int required = signature.required(); int actual = args.length; boolean restKwargs = blockBody instanceof IRBlockBody && ((IRBlockBody) blockBody).getSignature().hasKwargs(); // FIXME: This is a hot mess. restkwargs factors into destructing a single element array as // well. I just weaved it into this logic. // for procs and blocks, single array passed to multi-arg must be spread if ((signature != Signature.ONE_ARGUMENT && required != 0 && (isFixed || signature != Signature.OPTIONAL) || restKwargs) && actual == 1 && args[0].respondsTo("to_ary")) { IRubyObject newAry = Helpers.aryToAry(args[0]); // This is very common to yield in *IRBlockBody. When we tackle call protocol for blocks this // will combine. if (newAry.isNil()) { args = new IRubyObject[] {args[0]}; } else if (newAry instanceof RubyArray) { args = ((RubyArray) newAry).toJavaArrayMaybeUnsafe(); } else { throw context.runtime.newTypeError( args[0].getType().getName() + "#to_ary should return Array"); } actual = args.length; } // fixed arity > 0 with mismatch needs a new args array if (isFixed && required > 0 && required != actual) { IRubyObject[] newArgs = ArraySupport.newCopy(args, required); if (required > actual) { // Not enough required args pad. Helpers.fillNil(newArgs, actual, required, context.runtime); } args = newArgs; } return args; }
public void writeInvokers(File destination) throws IOException { for (InvokerDescriptor descriptor : invokerDescriptors) { byte[] invokerBytes = Helpers.defOffline( descriptor.getRubyName(), descriptor.getJavaName(), descriptor.getClassname(), descriptor.getInvokerName(), descriptor.getArity(), descriptor.getScope(), descriptor.getCallConfig(), descriptor.getFile(), descriptor.getLine()); if (VERIFY_CLASSFILES) CheckClassAdapter.verify(new ClassReader(invokerBytes), false, new PrintWriter(System.err)); writeClassFile(destination, invokerBytes, descriptor.getInvokerName()); } for (BlockCallbackDescriptor descriptor : blockCallbackDescriptors) { byte[] callbackBytes = Helpers.createBlockCallbackOffline( descriptor.getClassname(), descriptor.getMethod(), descriptor.getFile(), descriptor.getLine()); if (VERIFY_CLASSFILES) CheckClassAdapter.verify( new ClassReader(callbackBytes), false, new PrintWriter(System.err)); writeClassFile(destination, callbackBytes, descriptor.getCallbackName()); } for (BlockCallbackDescriptor descriptor : blockCallback19Descriptors) { byte[] callbackBytes = Helpers.createBlockCallback19Offline( descriptor.getClassname(), descriptor.getMethod(), descriptor.getFile(), descriptor.getLine()); if (VERIFY_CLASSFILES) CheckClassAdapter.verify( new ClassReader(callbackBytes), false, new PrintWriter(System.err)); writeClassFile(destination, callbackBytes, descriptor.getCallbackName()); } }
@JRubyMethod public IRubyObject parameters(ThreadContext context) { BlockBody body = this.getBlock().getBody(); return Helpers.argumentDescriptorsToParameters( context.runtime, body.getArgumentDescriptors(), isLambda()); }
@JRubyMethod( name = "raise", optional = 3, frame = true, module = true, visibility = Visibility.PRIVATE, omit = true) public static IRubyObject rbRaise( ThreadContext context, IRubyObject recv, IRubyObject[] args, Block block) { Ruby runtime = context.runtime; // Check for a Java exception ConcreteJavaProxy exception = null; if (args.length == 0 && runtime.getGlobalVariables().get("$!") instanceof ConcreteJavaProxy) { exception = (ConcreteJavaProxy) runtime.getGlobalVariables().get("$!"); } else if (args.length == 1 && args[0] instanceof ConcreteJavaProxy) { exception = (ConcreteJavaProxy) args[0]; } if (exception != null) { // looks like someone's trying to raise a Java exception. Let them. Object maybeThrowable = exception.getObject(); if (maybeThrowable instanceof Throwable) { // yes, we're cheating here. Helpers.throwException((Throwable) maybeThrowable); return recv; // not reached } else { throw runtime.newTypeError("can't raise a non-Throwable Java object"); } } else { return RubyKernel.raise(context, recv, args, block); } }
private IRubyObject doCallProcForObj(IRubyObject result) { if (proc != null) { // return the result of the proc, but not for symbols return Helpers.invoke(getRuntime().getCurrentContext(), proc, "call", result); } return result; }
@Override public IRubyObject interpret( Ruby runtime, ThreadContext context, IRubyObject self, Block aBlock) { RubyModule target = Helpers.checkIsModule(leftNode.interpret(runtime, context, self, aBlock)); IRubyObject value = getValue(context, target); return value != null ? value : target.getConstantFromConstMissing(name); }
@JRubyMethod(module = true) public static IRubyObject timeout( final ThreadContext context, IRubyObject timeout, IRubyObject seconds, IRubyObject exceptionType, Block block) { // No seconds, just yield if (seconds.isNil() || Helpers.invoke(context, seconds, "zero?").isTrue()) { return block.yieldSpecific(context); } final Ruby runtime = context.runtime; // No timeout in critical section if (runtime.getThreadService().getCritical()) { return raiseBecauseCritical(context); } final RubyThread currentThread = context.getThread(); final AtomicBoolean latch = new AtomicBoolean(false); IRubyObject id = new RubyObject(runtime, runtime.getObject()); RubyClass anonException = (RubyClass) runtime.getClassFromPath("Timeout::AnonymousException"); Runnable timeoutRunnable = exceptionType.isNil() ? prepareRunnable(currentThread, runtime, latch, id) : prepareRunnableWithException(currentThread, exceptionType, runtime, latch); Future timeoutFuture = null; try { try { timeoutFuture = timeoutExecutor.schedule( timeoutRunnable, (long) (seconds.convertToFloat().getDoubleValue() * 1000000), TimeUnit.MICROSECONDS); return block.yield(context, seconds); } finally { killTimeoutThread(context, timeoutFuture, latch); } } catch (RaiseException re) { // if it's the exception we're expecting if (re.getException().getMetaClass() == anonException) { // and we were not given a specific exception if (exceptionType.isNil()) { // and it's the exception intended for us if (re.getException().getInternalVariable("__identifier__") == id) { return raiseTimeoutError(context, re); } } } // otherwise, rethrow throw re; } }
@Override public IRubyObject interpret( Ruby runtime, ThreadContext context, IRubyObject self, Block aBlock) { IRubyObject result = super.interpret(runtime, context, self, aBlock); DynamicScope scope = context.getCurrentScope(); Helpers.updateScopeWithCaptures(context, scope, scopeOffsets, result); return result; }
private static RangeLike rangeValues(ThreadContext context, IRubyObject range) { RangeLike like = new RangeLike(); if (range instanceof RubyRange) { RubyRange vrange = (RubyRange) range; like.begin = vrange.first(context); like.end = vrange.last(context); like.excl = vrange.exclude_end_p().isTrue(); } else { if (!range.respondsTo("begin") || !range.respondsTo("end") || !range.respondsTo("exclude_end?")) { return null; } like.begin = Helpers.invoke(context, range, "begin"); like.end = Helpers.invoke(context, range, "end"); like.excl = Helpers.invoke(context, range, "exlucde_end?").isTrue(); } like.range = Helpers.invoke(context, like.end, "-", like.begin); return like; }
public IRubyObject callMethodMissing( CacheEntry entry, CallType callType, ThreadContext context, IRubyObject self, String name, IRubyObject[] args, Block block) { return Helpers.selectMethodMissing(context, self, entry.method.getVisibility(), name, callType) .call(context, self, self.getMetaClass(), name, args, block); }
/** * How many of the keywords listed happen to be required keyword args. Note: total kwargs - req * kwarg = opt kwargs. */ public int getRequiredKeywordCount() { if (getKeywordCount() < 1) return 0; int count = 0; for (int i = 0; i < getKeywordCount(); i++) { for (Node asgnNode : args[keywordsIndex + i].childNodes()) { if (Helpers.isRequiredKeywordArgumentValueNode(asgnNode)) count++; } } return count; }
protected IRubyObject case_aware_op_aset( ThreadContext context, IRubyObject key, final IRubyObject value, boolean caseSensitive) { if (!key.respondsTo("to_str")) { throw getRuntime().newTypeError("can't convert " + key.getMetaClass() + " into String"); } if (!value.respondsTo("to_str") && !value.isNil()) { throw getRuntime().newTypeError("can't convert " + value.getMetaClass() + " into String"); } if (!caseSensitive) { key = getCorrectKey(key, context); } if (value.isNil()) { return super.delete(context, key, org.jruby.runtime.Block.NULL_BLOCK); } IRubyObject keyAsStr = normalizeEnvString(Helpers.invoke(context, key, "to_str")); IRubyObject valueAsStr = value.isNil() ? context.nil : normalizeEnvString(Helpers.invoke(context, value, "to_str")); if (updateRealENV) { POSIX posix = context.runtime.getPosix(); String keyAsJava = keyAsStr.asJavaString(); // libc (un)setenv is not reentrant, so we need to synchronize across the entire JVM // (JRUBY-5933) if (valueAsStr == context.nil) { synchronized (Object.class) { posix.unsetenv(keyAsJava); } } else { synchronized (Object.class) { posix.setenv(keyAsJava, valueAsStr.asJavaString(), 1); } } } return super.op_aset(context, keyAsStr, valueAsStr); }
private static Block getBlockPassBlock( Node blockNode, Ruby runtime, ThreadContext context, IRubyObject self, Block currentBlock) { Node bodyNode = ((BlockPassNode) blockNode).getBodyNode(); IRubyObject proc; if (bodyNode == null) { proc = runtime.getNil(); } else { proc = bodyNode.interpret(runtime, context, self, currentBlock); } return Helpers.getBlockFromBlockPassBody(proc, currentBlock); }
@Override public IRubyObject interpret( Ruby runtime, ThreadContext context, IRubyObject self, Block aBlock) { IRubyObject receiver = getReceiverNode().interpret(runtime, context, self, aBlock); return callAdapter.callIter( context, self, receiver, arg1.interpret(runtime, context, self, aBlock), arg2.interpret(runtime, context, self, aBlock), Helpers.getBlock(context, self, iterNode)); }
public static InetAddress getRubyInetAddress(ByteList address) throws UnknownHostException { // switched to String because the ByteLists were not comparing properly in 1.9 mode (encoding? // FIXME: Need to properly decode this string (see Helpers.decodeByteList) String addressString = Helpers.byteListToString(address); if (addressString.equals(BROADCAST)) { return InetAddress.getByAddress(INADDR_BROADCAST); } else if (addressString.equals(ANY)) { return InetAddress.getByAddress(INADDR_ANY); } else { return InetAddress.getByName(addressString); } }
@Override public RubyString definition( Ruby runtime, ThreadContext context, IRubyObject self, Block aBlock) { IRubyObject lastError = context.getErrorInfo(); try { if (Helpers.isModuleAndHasConstant( leftNode.interpret(runtime, context, self, aBlock), name)) { return runtime.getDefinedMessage(DefinedMessage.CONSTANT); } } catch (JumpException e) { // replace lastError context.setErrorInfo(lastError); } return null; }
// c: rb_random_real public static double randomReal(ThreadContext context, IRubyObject obj) { RandomType random = null; if (obj.equals(context.runtime.getRandomClass())) { random = getDefaultRand(context); } if (obj instanceof RubyRandom) { random = ((RubyRandom) obj).random; } if (random != null) { return random.genrandReal(); } double d = RubyNumeric.num2dbl(Helpers.invoke(context, obj, "rand")); if (d < 0.0 || d >= 1.0) { throw context.runtime.newRangeError("random number too big: " + d); } return d; }
public IRubyObject dispatch( String method_name, IRubyObject arg1, IRubyObject arg2, IRubyObject arg3, IRubyObject arg4, IRubyObject arg5) { return Helpers.invoke( context, ripper, method_name, escape(arg1), escape(arg2), escape(arg3), escape(arg4), escape(arg5)); }
@JRubyMethod(name = "ruby", meta = true) public static IRubyObject ruby(ThreadContext context, IRubyObject recv) { Ruby runtime = context.runtime; RubyHash configHash = (RubyHash) runtime.getModule("RbConfig").getConstant("CONFIG"); IRubyObject bindir = configHash.op_aref(context, runtime.newString("bindir")); IRubyObject ruby_install_name = configHash.op_aref(context, runtime.newString("ruby_install_name")); IRubyObject exeext = configHash.op_aref(context, runtime.newString("EXEEXT")); return Helpers.invoke( context, runtime.getClass("File"), "join", bindir, ruby_install_name.callMethod(context, "+", exeext)); }
/** * For handling all non-Ruby exceptions bubbling out of threads * * @param exception */ @SuppressWarnings("deprecation") public void exceptionRaised(Throwable exception) { if (exception instanceof RaiseException) { exceptionRaised((RaiseException) exception); return; } assert isCurrent(); Ruby runtime = getRuntime(); if (abortOnException(runtime) && exception instanceof Error) { // re-propagate on main thread runtime.getThreadService().getMainThread().getNativeThread().stop(exception); } else { // just rethrow on this thread, let system handlers report it Helpers.throwException(exception); } }
@JRubyMethod(module = true) public static IRubyObject timeout( final ThreadContext context, IRubyObject timeout, IRubyObject seconds, Block block) { // No seconds, just yield if (seconds.isNil() || Helpers.invoke(context, seconds, "zero?").isTrue()) { return block.yieldSpecific(context); } final Ruby runtime = context.runtime; // No timeout in critical section if (runtime.getThreadService().getCritical()) { return raiseBecauseCritical(context); } final RubyThread currentThread = context.getThread(); final AtomicBoolean latch = new AtomicBoolean(false); IRubyObject id = new RubyObject(runtime, runtime.getObject()); Runnable timeoutRunnable = prepareRunnable(currentThread, runtime, latch, id); Future timeoutFuture = null; try { try { timeoutFuture = timeoutExecutor.schedule( timeoutRunnable, (long) (seconds.convertToFloat().getDoubleValue() * 1000000), TimeUnit.MICROSECONDS); return block.yield(context, seconds); } finally { killTimeoutThread(context, timeoutFuture, latch); } } catch (RaiseException re) { if (re.getException().getInternalVariable("__identifier__") == id) { return raiseTimeoutError(context, re); } else { throw re; } } }
private static JavaClass getTargetType(ThreadContext context, Ruby runtime, IRubyObject type) { JavaClass targetType; if (type instanceof RubyString || type instanceof RubySymbol) { targetType = runtime.getJavaSupport().getNameClassMap().get(type.asJavaString()); if (targetType == null) targetType = JavaClass.forNameVerbose(runtime, type.asJavaString()); } else if (type instanceof RubyModule && type.respondsTo("java_class")) { targetType = (JavaClass) Helpers.invoke(context, type, "java_class"); } else if (type instanceof JavaProxy) { if (((JavaProxy) type).getObject() instanceof Class) { targetType = JavaClass.get(runtime, (Class) ((JavaProxy) type).getObject()); } else { throw runtime.newTypeError("not a valid target type: " + type); } } else { throw runtime.newTypeError("unable to convert to type: " + type); } return targetType; }
// ENEBO: Some of this logic should be put back into the Nodes themselves, but the more // esoteric features of 1.9 make this difficult to know how to do this yet. public BlockBody newCompiledBlockBody19(ThreadContext context, IterNode iterNode) { final ArgsNode argsNode = (ArgsNode) iterNode.getVarNode(); boolean hasMultipleArgsHead = false; if (iterNode.getVarNode() instanceof MultipleAsgnNode) { hasMultipleArgsHead = ((MultipleAsgnNode) iterNode.getVarNode()).getHeadNode() != null; } NodeType argsNodeId = BlockBody.getArgumentTypeWackyHack(iterNode); return new CompiledBlock19( ((ArgsNode) iterNode.getVarNode()).getArity(), iterNode.getScope(), compileBlock19( context, new StandardASMCompiler("blahfooblah" + System.currentTimeMillis(), "blahfooblah"), iterNode), hasMultipleArgsHead, BlockBody.asArgumentType(argsNodeId), Helpers.encodeParameterList(argsNode).split(";")); }
private IRubyObject invokeRuby( final DynamicMethod method, final JavaProxyMethod proxyMethod, final RubyClass metaClass, final String name, final Object[] nargs) { final IRubyObject[] newArgs = new IRubyObject[nargs.length]; for (int i = nargs.length; --i >= 0; ) { newArgs[i] = JavaUtil.convertJavaToUsableRubyObject(runtime, nargs[i]); } final int arity = method.getArity().getValue(); if (arity < 0 || arity == newArgs.length) { final ThreadContext context = runtime.getCurrentContext(); return method.call(context, self, metaClass, name, newArgs); } if (proxyMethod.hasSuperImplementation()) { final ThreadContext context = runtime.getCurrentContext(); final RubyClass superClass = metaClass.getSuperClass(); return Helpers.invokeAs(context, superClass, self, name, newArgs, Block.NULL_BLOCK); } throw runtime.newArgumentError(newArgs.length, arity); }
public void endScript(boolean generateLoad, boolean generateMain) { // add Script#run impl, used for running this script with a specified threadcontext and self // root method of a script is always in __file__ method String methodName = "__file__"; String loadSig = sig(IRubyObject.class, ThreadContext.class, IRubyObject.class, boolean.class); if (generateLoad || generateMain) { // the load method is used for loading as a top-level script, and prepares appropriate scoping // around the code SkinnyMethodAdapter method = new SkinnyMethodAdapter(getClassVisitor(), ACC_PUBLIC, "load", loadSig, null, null); method.start(); // invoke __file__ with threadcontext, self, args (null), and block (null) Label tryBegin = new Label(); Label tryFinally = new Label(); method.label(tryBegin); method.aload(THREADCONTEXT_INDEX); String scopeNames = Helpers.encodeScope(topLevelScope); method.ldc(scopeNames); method.iload(SELF_INDEX + 1); method.invokestatic( p(Helpers.class), "preLoad", sig(StaticScope.class, ThreadContext.class, String.class, boolean.class)); // store root scope method.aload(THIS); method.swap(); method.invokevirtual( p(AbstractScript.class), "setRootScope", sig(void.class, StaticScope.class)); method.aload(THIS); method.aload(THREADCONTEXT_INDEX); method.aload(SELF_INDEX); method.getstatic(p(IRubyObject.class), "NULL_ARRAY", ci(IRubyObject[].class)); method.getstatic(p(Block.class), "NULL_BLOCK", ci(Block.class)); method.invokestatic(getClassname(), methodName, getStaticMethodSignature(getClassname(), 4)); method.aload(THREADCONTEXT_INDEX); method.invokestatic(p(Helpers.class), "postLoad", sig(void.class, ThreadContext.class)); method.areturn(); method.label(tryFinally); method.aload(THREADCONTEXT_INDEX); method.invokestatic(p(Helpers.class), "postLoad", sig(void.class, ThreadContext.class)); method.athrow(); method.trycatch(tryBegin, tryFinally, tryFinally, null); method.end(); } if (generateMain) { // add main impl, used for detached or command-line execution of this script with a new // runtime // root method of a script is always in stub0, method0 SkinnyMethodAdapter method = new SkinnyMethodAdapter( getClassVisitor(), ACC_PUBLIC | ACC_STATIC, "main", sig(Void.TYPE, params(String[].class)), null, null); method.start(); // init script filename to simple class name in case we don't assign it (null ClassLoader) method.ldc(getClassname().replaceAll("\\\\.", "/")); method.astore(1); // new instance to invoke run against method.newobj(getClassname()); method.dup(); method.invokespecial(getClassname(), "<init>", sig(Void.TYPE)); // guard against null classloader method.ldc(Type.getType("L" + getClassname() + ";")); method.invokevirtual(p(Class.class), "getClassLoader", sig(ClassLoader.class)); Label skip = new Label(); method.ifnull(skip); // set filename for the loaded script class (JRUBY-4825) method.dup(); method.ldc(Type.getType("L" + getClassname() + ";")); method.invokevirtual(p(Class.class), "getClassLoader", sig(ClassLoader.class)); method.ldc(getClassname() + ".class"); method.invokevirtual(p(ClassLoader.class), "getResource", sig(URL.class, String.class)); method.invokevirtual(p(Object.class), "toString", sig(String.class)); method.astore(1); method.aload(1); method.invokevirtual(p(AbstractScript.class), "setFilename", sig(void.class, String.class)); // ifnull ClassLoader method.label(skip); // instance config for the script run method.newobj(p(RubyInstanceConfig.class)); method.dup(); method.invokespecial(p(RubyInstanceConfig.class), "<init>", "()V"); // set argv from main's args method.dup(); method.aload(0); method.invokevirtual(p(RubyInstanceConfig.class), "setArgv", sig(void.class, String[].class)); // set script filename ($0) method.dup(); method.aload(1); method.invokevirtual( p(RubyInstanceConfig.class), "setScriptFileName", sig(void.class, String.class)); // invoke run with threadcontext and topself method.invokestatic(p(Ruby.class), "newInstance", sig(Ruby.class, RubyInstanceConfig.class)); method.dup(); method.invokevirtual(RUBY, "getCurrentContext", sig(ThreadContext.class)); method.swap(); method.invokevirtual(RUBY, "getTopSelf", sig(IRubyObject.class)); method.ldc(false); method.invokevirtual(getClassname(), "load", loadSig); method.voidreturn(); method.end(); } getCacheCompiler().finish(); endInit(); endClassInit(); }
/** num_to_int */ @JRubyMethod(name = "to_int") public IRubyObject to_int(ThreadContext context) { return Helpers.invoke(context, this, "to_i"); }
public IRubyObject dispatch(String method_name) { return Helpers.invoke(context, ripper, method_name); }
public IRubyObject dispatch(String method_name, IRubyObject arg1) { return Helpers.invoke(context, ripper, method_name, escape(arg1)); }
public static String buildStaticScopeNames(StaticScope scope) { return Helpers.encodeScope(scope); }
private static IRubyObject interpret( ThreadContext context, IRubyObject self, IRScope scope, Visibility visibility, RubyModule implClass, IRubyObject[] args, Block block, Block.Type blockType) { Instr[] instrs = scope.getInstrsForInterpretation(); // The base IR may not have been processed yet if (instrs == null) instrs = scope.prepareForInterpretation(blockType == Block.Type.LAMBDA); int numTempVars = scope.getTemporaryVariableSize(); Object[] temp = numTempVars > 0 ? new Object[numTempVars] : null; int n = instrs.length; int ipc = 0; Instr instr = null; Object exception = null; int kwArgHashCount = (scope.receivesKeywordArgs() && args[args.length - 1] instanceof RubyHash) ? 1 : 0; DynamicScope currDynScope = context.getCurrentScope(); // Counter tpCount = null; // Init profiling this scope boolean debug = IRRuntimeHelpers.isDebug(); boolean profile = IRRuntimeHelpers.inProfileMode(); Integer scopeVersion = profile ? initProfiling(scope) : 0; // Enter the looooop! while (ipc < n) { instr = instrs[ipc]; ipc++; Operation operation = instr.getOperation(); if (debug) { LOG.info("I: {}", instr); interpInstrsCount++; } else if (profile) { if (operation.modifiesCode()) codeModificationsCount++; interpInstrsCount++; /* Counter cnt = opStats.get(operation); if (cnt == null) { cnt = new Counter(); opStats.put(operation, cnt); } cnt.count++; */ } try { switch (operation.opClass) { case ARG_OP: { receiveArg( context, instr, operation, args, kwArgHashCount, currDynScope, temp, exception, block); break; } case BRANCH_OP: { if (operation == Operation.JUMP) { ipc = ((JumpInstr) instr).getJumpTarget().getTargetPC(); } else { ipc = instr.interpretAndGetNewIPC(context, currDynScope, self, temp, ipc); } break; } case CALL_OP: { if (profile) updateCallSite(instr, scope, scopeVersion); processCall( context, instr, operation, scope, currDynScope, temp, self, block, blockType); break; } case BOOK_KEEPING_OP: { switch (operation) { case PUSH_FRAME: { context.preMethodFrameAndClass( implClass, scope.getName(), self, block, scope.getStaticScope()); context.setCurrentVisibility(visibility); break; } case PUSH_BINDING: { // SSS NOTE: Method scopes only! // // Blocks are a headache -- so, these instrs. are only added to IRMethods. // Blocks have more complicated logic for pushing a dynamic scope (see // InterpretedIRBlockBody) // Changed by DPR currDynScope = DynamicScope.newDynamicScope( scope.getStaticScope(), context.getCurrentScope().getDepth()); context.pushScope(currDynScope); break; } case CHECK_ARITY: ((CheckArityInstr) instr).checkArity(context.runtime, args.length); break; case POP_FRAME: context.popFrame(); context.popRubyClass(); break; case POP_BINDING: context.popScope(); break; case THREAD_POLL: if (profile) { // SSS: Not being used currently // tpCount.count++; globalThreadPollCount++; // 20K is arbitrary // Every 20K profile counts, spit out profile stats if (globalThreadPollCount % 20000 == 0) { analyzeProfile(); // outputProfileStats(); } } context.callThreadPoll(); break; case LINE_NUM: context.setLine(((LineNumberInstr) instr).lineNumber); break; case RECORD_END_BLOCK: ((RecordEndBlockInstr) instr).interpret(); break; } break; } case OTHER_OP: { Object result = null; switch (operation) { // --------- Return flavored instructions -------- case BREAK: { BreakInstr bi = (BreakInstr) instr; IRubyObject rv = (IRubyObject) bi.getReturnValue().retrieve(context, self, currDynScope, temp); // This also handles breaks in lambdas -- by converting them to a return return IRRuntimeHelpers.initiateBreak( context, scope, bi.getScopeToReturnTo().getScopeId(), rv, blockType); } case RETURN: { return (IRubyObject) retrieveOp( ((ReturnBase) instr).getReturnValue(), context, self, currDynScope, temp); } case NONLOCAL_RETURN: { NonlocalReturnInstr ri = (NonlocalReturnInstr) instr; IRubyObject rv = (IRubyObject) retrieveOp(ri.getReturnValue(), context, self, currDynScope, temp); ipc = n; // If not in a lambda, check if this was a non-local return if (!IRRuntimeHelpers.inLambda(blockType)) { IRRuntimeHelpers.initiateNonLocalReturn( context, scope, ri.methodToReturnFrom, rv); } return rv; } // ---------- Common instruction --------- case COPY: { CopyInstr c = (CopyInstr) instr; result = retrieveOp(c.getSource(), context, self, currDynScope, temp); setResult(temp, currDynScope, c.getResult(), result); break; } case GET_FIELD: { GetFieldInstr gfi = (GetFieldInstr) instr; IRubyObject object = (IRubyObject) gfi.getSource().retrieve(context, self, currDynScope, temp); VariableAccessor a = gfi.getAccessor(object); result = a == null ? null : (IRubyObject) a.get(object); if (result == null) { result = context.nil; } setResult(temp, currDynScope, gfi.getResult(), result); break; } case SEARCH_CONST: { SearchConstInstr sci = (SearchConstInstr) instr; result = sci.getCachedConst(); if (!sci.isCached(context, result)) result = sci.cache(context, currDynScope, self, temp); setResult(temp, currDynScope, sci.getResult(), result); break; } // ---------- All the rest --------- default: result = instr.interpret(context, currDynScope, self, temp, block); setResult(temp, currDynScope, instr, result); break; } break; } } } catch (Throwable t) { // Unrescuable: // IRReturnJump, ThreadKill, RubyContinuation, MainExitException, etc. // These cannot be rescued -- only run ensure blocks // // Others: // IRBreakJump, Ruby exceptions, errors, and other java exceptions. // These can be rescued -- run rescue blocks if (debug) LOG.info( "in scope: " + scope + ", caught Java throwable: " + t + "; excepting instr: " + instr); ipc = (t instanceof Unrescuable) ? scope.getEnsurerPC(instr) : scope.getRescuerPC(instr); if (debug) LOG.info("ipc for rescuer/ensurer: " + ipc); if (ipc == -1) { Helpers.throwException((Throwable) t); } else { exception = t; } } } // Control should never get here! // SSS FIXME: But looks like BEGIN/END blocks get here -- needs fixing return null; }