public static CallSite fixnumBooleanBootstrap(Lookup lookup, String name, MethodType type, long value, String file, int line) throws NoSuchMethodException, IllegalAccessException { String[] names = name.split(":"); String operator = JavaNameMangler.demangleMethodName(names[1]); JRubyCallSite site = new JRubyCallSite(lookup, type, CallType.NORMAL, file, line, operator, false, false, true); MethodHandle target = lookup.findStatic(MathLinker.class, "fixnumBoolean", methodType(boolean.class, ThreadContext.class, IRubyObject.class, IRubyObject.class, JRubyCallSite.class, long.class)); target = insertArguments(target, 3, site, value); site.setTarget(target); return site; }
public static IRubyObject invocationFallback(JRubyCallSite site, ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2) throws Throwable { RubyClass selfClass = pollAndGetClass(context, self); String method = site.name(); SwitchPoint switchPoint = (SwitchPoint)selfClass.getInvalidator().getData(); CacheEntry entry = selfClass.searchWithCache(method); if (methodMissing(entry, site.callType(), method, caller)) { IRubyObject mmResult = callMethodMissing(entry, site.callType(), context, self, method, arg0, arg1, arg2); // TODO: replace with handle logic return site.isAttrAssign() ? arg2 : mmResult; } MethodHandle target = getTarget(site, selfClass, entry, 3); target = updateInvocationTarget(target, site, self, selfClass, method, entry, switchPoint, false, 3); return (IRubyObject)target.invokeWithArguments(context, caller, self, arg0, arg1, arg2); }
@Override public boolean canGenerate(JRubyCallSite site, RubyClass cls, DynamicMethod method) { NativeCall nativeCall = method.getNativeCall(); if (nativeCall != null) { int nativeArgCount = getNativeArgCount(method, method.getNativeCall()); // arity must match or both be [] args if (nativeArgCount != site.arity()) { throw new IndirectBindingException("arity mismatch or varargs at call site: " + nativeArgCount + " != " + site.arity()); } return true; } return false; }
String method = JavaNameMangler.demangleMethodName(names[1]); if (operation.equals("call")) { site = new JRubyCallSite(lookup, type, CallType.NORMAL, file, line, method, false, false, true); } else if (operation.equals("fcall")) { site = new JRubyCallSite(lookup, type, CallType.FUNCTIONAL, file, line, method, false, false, true); } else if (operation.equals("vcall")) { site = new JRubyCallSite(lookup, type, CallType.VARIABLE, file, line, method, false, false, true); } else if (operation.equals("callIter")) { site = new JRubyCallSite(lookup, type, CallType.NORMAL, file, line, method, false, true, true); } else if (operation.equals("fcallIter")) { site = new JRubyCallSite(lookup, type, CallType.FUNCTIONAL, file, line, method, false, true, true); } else if (operation.equals("vcallIter")) { site = new JRubyCallSite(lookup, type, CallType.VARIABLE, file, line, method, false, true, true); } else if (operation.equals("attrAssign")) { site = new JRubyCallSite(lookup, type, CallType.NORMAL, file, line, method, true, false, false); } else if (operation.equals("attrAssignSelf")) { site = new JRubyCallSite(lookup, type, CallType.VARIABLE, file, line, method, true, false, false); } else if (operation.equals("attrAssignExpr")) { site = new JRubyCallSite(lookup, type, CallType.NORMAL, file, line, method, true, false, true); } else if (operation.equals("attrAssignSelfExpr")) { site = new JRubyCallSite(lookup, type, CallType.VARIABLE, file, line, method, true, false, true); } else { throw new RuntimeException("wrong invokedynamic target: " + name); site); site.setInitialTarget(myFallback); return site;
public static IRubyObject floatOperator(ThreadContext context, IRubyObject caller, IRubyObject self, JRubyCallSite site, double value) throws Throwable { String operator = site.name(); String opMethod = MethodIndex.getFastFloatOpsMethod(operator); String name = "float_" + opMethod; test = permuteArguments(test, methodType(boolean.class, ThreadContext.class, IRubyObject.class, IRubyObject.class), new int[] {2}); if (LOG_BINDING) LOG.debug(name + "\tFloat operation at site #" + site.siteID() + " (" + site.file() + ":" + site.line() + ") bound directly"); site.setTarget(guardWithTest(test, target, fallback)); .guardWithTest(target, fallback); site.setTarget(target);
site.clearCount() > RubyInstanceConfig.MAX_FAIL_COUNT || (!site.hasSeenType(selfClass.id) && site.seenTypesCount() + 1 > RubyInstanceConfig.MAX_POLY_COUNT)) { site.setTarget(target = createFail((block?FAILS_B:FAILS)[arity], site, name, entry.method)); } else { target = postProcess(site, target); if (site.seenTypesCount() > 0 && site.getTarget() != null && !site.hasSeenType(selfClass.id)) { fallback = site.getTarget(); curry = false; } else { String bind = site.boundOnce() ? "rebind" : "bind"; if (RubyInstanceConfig.LOG_INDY_BINDINGS) LOG.info(name + "\ttriggered site #" + site.siteID() + " " + bind + " (" + site.file() + ":" + site.line() + ")"); fallback = (block?FALLBACKS_B:FALLBACKS)[arity]; site.clearTypes(); curry = true; site.addType(selfClass.id); .from(site.signature().asFold(boolean.class)) .permute("self"); site.setTarget(gwt);
public static IRubyObject fixnumOperatorFail(ThreadContext context, IRubyObject caller, IRubyObject self, JRubyCallSite site, RubyFixnum value) throws Throwable { String operator = site.name(); RubyClass selfClass = InvokeDynamicSupport.pollAndGetClass(context, self); CacheEntry entry = site.entry; if (entry.typeOk(selfClass)) { return entry.method.call(context, self, selfClass, operator, value); } else { entry = selfClass.searchWithCache(operator); if (InvokeDynamicSupport.methodMissing(entry, site.callType(), operator, caller)) { return InvokeDynamicSupport.callMethodMissing(entry, site.callType(), context, self, operator, value); } site.entry = entry; return entry.method.call(context, self, selfClass, operator, value); } }
public static IRubyObject invocationFallback(JRubyCallSite site, ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject arg0, Block block) throws Throwable { RubyClass selfClass = pollAndGetClass(context, self); String method = site.name(); SwitchPoint switchPoint = (SwitchPoint)selfClass.getInvalidator().getData(); CacheEntry entry = selfClass.searchWithCache(method); if (methodMissing(entry, site.callType(), method, caller)) { try { return callMethodMissing(entry, site.callType(), context, self, method, arg0, block); } catch (JumpException.BreakJump bj) { return handleBreakJump(context, bj); } catch (JumpException.RetryJump rj) { return retryJumpError(context); } finally { if (site.isIterator()) block.escape(); } } MethodHandle target = getTarget(site, selfClass, entry, 1); target = updateInvocationTarget(target, site, self, selfClass, method, entry, switchPoint, true, 1); return (IRubyObject) target.invokeWithArguments(context, caller, self, arg0, block); }
@Override public MethodHandle generate(JRubyCallSite site, RubyClass cls, DynamicMethod method, String realName) { // Ruby to Ruby if (RubyInstanceConfig.LOG_INDY_BINDINGS) LOG.info(site.name() + "\tbound to Ruby method " + logMethod(method) + ": " + method.getNativeCall()); return postProcessNativeHandle(createRubyHandle(site, method, realName), site, method, true, false); }
@Override public MethodHandle generate(JRubyCallSite site, RubyClass cls, DynamicMethod method, String realName) { MethodHandle handle = ((HandleMethod)method).getHandle(site.arity()); if (handle == null) { throw new IndirectBindingException("MH dynamic method does not have needed arity"); } if (RubyInstanceConfig.LOG_INDY_BINDINGS) LOG.info(site.name() + "\tbound from MHDynMethod " + logMethod(method) + ":" + handle); Signature fullSig = site.fullSignature(); MethodHandle nativeTarget = Binder .from(fullSig.type()) .permute(fullSig.to("context", "self", "arg*", "block")) .invoke(handle); nativeTarget = addOrRemoveBlock(site, nativeTarget); return nativeTarget; } }
int nativeArgCount = getNativeArgCount(method, method.getNativeCall()); if (nativeArgCount == 4 && site.arity() == 4) { .from(site.type().changeReturnType(void.class)) .insert(0, new Class[]{int.class, int.class, boolean.class}, required, optional, rest) .invokeStaticQuiet(site.lookup(), InvocationLinker.class, "checkArity"); nativeTarget = foldArguments(nativeTarget, arityCheck); SmartHandle rewriteHandle = SmartBinder.from(lookup(), site.signature().insertArg(0, "throwable", Throwable.class)) .permute("throwable") .append("runtime", method.getImplementationClass().getRuntime())
@Override public boolean canGenerate(JRubyCallSite site, RubyClass cls, DynamicMethod method) { NativeCall nativeCall = method.getNativeCall(); if (nativeCall != null) { // has an explicit native call path if (nativeCall.isJava()) { if (!RubyInstanceConfig.INVOKEDYNAMIC_JAVA) { throw new IndirectBindingException("direct Java dispatch not enabled"); } // if Java, must: // * match arity <= 3 // * not be passed a block (no coercion yet) // * be a normal wrapper around a class or module (not a Ruby subclass) if (nativeCall.getNativeSignature().length != site.arity() || site.arity() > 3 || site.isIterator() || !cls.getJavaProxy()) { throw new IndirectBindingException("Java call arity mismatch or > 3 args"); } return true; } } return false; }
@Override public boolean canGenerate(JRubyCallSite site, RubyClass cls, DynamicMethod method) { if (method instanceof org.jruby.ext.ffi.jffi.DefaultMethod || method instanceof org.jruby.ext.ffi.jffi.JITNativeInvoker) { // if frame/scope required, can't dispatch direct if (method.getCallConfig() != CallConfiguration.FrameNoneScopeNone) { throw new IndirectBindingException("frame or scope required: " + method.getCallConfig()); } if (!method.getArity().isFixed()) { throw new IndirectBindingException("fixed arity required: " + method.getArity()); } // Arity must match, otherwise let the indirect method process errors if (method.getArity().getValue() != site.arity()) { throw new IndirectBindingException("arity mismatch"); } // Only support 0..6 parameters if (method.getArity().getValue() > 6) { throw new IndirectBindingException("target args > 6"); } if (site.type().parameterType(site.type().parameterCount() - 1) == Block.class) { // Called with a block to substitute for a callback param - cannot bind directly throw new IndirectBindingException("callback block supplied"); } return true; } return false; }
public static IRubyObject floatOperator(ThreadContext context, IRubyObject caller, IRubyObject self, JRubyCallSite site, double value) throws Throwable { String operator = site.name(); String opMethod = MethodIndex.getFastFloatOpsMethod(operator); String name = "float_" + opMethod; test = permuteArguments(test, methodType(boolean.class, ThreadContext.class, IRubyObject.class, IRubyObject.class), new int[] {2}); if (LOG_BINDING) LOG.debug(name + "\tFloat operation at site #" + site.siteID() + " (" + site.file() + ":" + site.line() + ") bound directly"); site.setTarget(guardWithTest(test, target, fallback)); .guardWithTest(target, fallback); site.setTarget(target);
site.clearCount() > RubyInstanceConfig.MAX_FAIL_COUNT || (!site.hasSeenType(selfClass.id) && site.seenTypesCount() + 1 > RubyInstanceConfig.MAX_POLY_COUNT)) { site.setTarget(target = createFail((block?FAILS_B:FAILS)[arity], site, name, entry.method)); } else { target = postProcess(site, target); if (site.seenTypesCount() > 0 && site.getTarget() != null && !site.hasSeenType(selfClass.id)) { fallback = site.getTarget(); curry = false; } else { String bind = site.boundOnce() ? "rebind" : "bind"; if (RubyInstanceConfig.LOG_INDY_BINDINGS) LOG.info(name + "\ttriggered site #" + site.siteID() + " " + bind + " (" + site.file() + ":" + site.line() + ")"); fallback = (block?FALLBACKS_B:FALLBACKS)[arity]; site.clearTypes(); curry = true; site.addType(selfClass.id); .from(site.signature().asFold(boolean.class)) .permute("self"); site.setTarget(gwt);
public static IRubyObject fail(JRubyCallSite site, ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject arg0, IRubyObject arg1, IRubyObject arg2) throws Throwable { RubyClass selfClass = pollAndGetClass(context, self); String name = site.name(); CacheEntry entry = site.entry; if (entry.typeOk(selfClass)) { return entry.method.call(context, self, selfClass, name, arg0, arg1, arg2); } else { entry = selfClass.searchWithCache(name); if (methodMissing(entry, site.callType(), name, caller)) { return callMethodMissing(entry, site.callType(), context, self, name, arg0, arg1, arg2); } site.entry = entry; return entry.method.call(context, self, selfClass, name, arg0, arg1, arg2); } }
public static IRubyObject invocationFallback(JRubyCallSite site, ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject arg0, IRubyObject arg1, Block block) throws Throwable { RubyClass selfClass = pollAndGetClass(context, self); String method = site.name(); SwitchPoint switchPoint = (SwitchPoint)selfClass.getInvalidator().getData(); CacheEntry entry = selfClass.searchWithCache(method); if (methodMissing(entry, site.callType(), method, caller)) { try { return callMethodMissing(entry, site.callType(), context, self, method, arg0, arg1, block); } catch (JumpException.BreakJump bj) { return handleBreakJump(context, bj); } catch (JumpException.RetryJump rj) { return retryJumpError(context); } finally { if (site.isIterator()) block.escape(); } } MethodHandle target = getTarget(site, selfClass, entry, 2); target = updateInvocationTarget(target, site, self, selfClass, method, entry, switchPoint, true, 2); return (IRubyObject) target.invokeWithArguments(context, caller, self, arg0, arg1, block); }
@Override public MethodHandle generate(JRubyCallSite site, RubyClass cls, DynamicMethod method, String realName) { // Ruby to Ruby if (RubyInstanceConfig.LOG_INDY_BINDINGS) LOG.info(site.name() + "\tbound to Ruby method " + logMethod(method) + ": " + method.getNativeCall()); return postProcessNativeHandle(createRubyHandle(site, method, realName), site, method, true, false); }
@Override public MethodHandle generate(JRubyCallSite site, RubyClass cls, DynamicMethod method, String realName) { MethodHandle handle = ((HandleMethod)method).getHandle(site.arity()); if (handle == null) { throw new IndirectBindingException("MH dynamic method does not have needed arity"); } if (RubyInstanceConfig.LOG_INDY_BINDINGS) LOG.info(site.name() + "\tbound from MHDynMethod " + logMethod(method) + ":" + handle); Signature fullSig = site.fullSignature(); MethodHandle nativeTarget = Binder .from(fullSig.type()) .permute(fullSig.to("context", "self", "arg*", "block")) .invoke(handle); nativeTarget = addOrRemoveBlock(site, nativeTarget); return nativeTarget; } }
int nativeArgCount = getNativeArgCount(method, method.getNativeCall()); if (nativeArgCount == 4 && site.arity() == 4) { .from(site.type().changeReturnType(void.class)) .insert(0, new Class[]{int.class, int.class, boolean.class}, required, optional, rest) .invokeStaticQuiet(site.lookup(), InvocationLinker.class, "checkArity"); nativeTarget = foldArguments(nativeTarget, arityCheck); SmartHandle rewriteHandle = SmartBinder.from(lookup(), site.signature().insertArg(0, "throwable", Throwable.class)) .permute("throwable") .append("runtime", method.getImplementationClass().getRuntime())