private static MethodHandle tryDispatchDirect(JRubyCallSite site, RubyClass cls, DynamicMethod method) { String[] realName = {site.name()}; method = unwrapMethod(method, realName); for (HandleGenerator generator : HANDLE_GENERATORS) { if (generator.canGenerate(site, cls, method)) { return generator.generate(site, cls, method, realName[0]); } } throw new IndirectBindingException("no direct path available for " + method.getClass().getName()); }
@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) { 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; }
@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; }
private static MethodHandle getTarget(JRubyCallSite site, RubyClass cls, CacheEntry entry, int arity) { IndirectBindingException ibe; try { return tryDispatchDirect(site, cls, entry.method); } catch (IndirectBindingException _ibe) { ibe = _ibe; // proceed with indirect, if enabled } // if indirect indy-bound methods (via DynamicMethod.call) are disabled, bail out if (!RubyInstanceConfig.INVOKEDYNAMIC_INDIRECT) { if (RubyInstanceConfig.LOG_INDY_BINDINGS) LOG.info(site.name() + "\tfailed to bind to " + logMethod(entry.method) + ": " + ibe.getMessage()); return null; } // no direct native path, use DynamicMethod.call if (RubyInstanceConfig.LOG_INDY_BINDINGS) LOG.info(site.name() + "\tbound indirectly to " + logMethod(entry.method) + ": " + ibe.getMessage()); MethodHandle dynMethodTarget = getDynamicMethodTarget(site.type(), arity, entry.method); dynMethodTarget = insertArguments(dynMethodTarget, 4, site.name()); dynMethodTarget = insertArguments(dynMethodTarget, 0, entry.method); return dynMethodTarget; }
public static DynamicMethod unwrapMethod(DynamicMethod method, String[] realName) throws IndirectBindingException { // get the "real" method in a few ways while (method instanceof AliasMethod) { realName[0] = ((AliasMethod)method).getOldName(); // need to use original name, not aliased name method = method.getRealMethod(); } while (method instanceof WrapperMethod) method = method.getRealMethod(); // ProfilingDynamicMethod wraps any number of other types of methods but // we do not handle it in indy binding right now. Disable direct binding // and bind through DynamicMethod. if (method instanceof ProfilingDynamicMethod) { throw new IndirectBindingException("profiling active"); } if (method instanceof DefaultMethod) { DefaultMethod defaultMethod = (DefaultMethod) method; if (defaultMethod.getMethodForCaching() instanceof JittedMethod) { method = defaultMethod.getMethodForCaching(); } } return method; }
private static MethodHandle getTarget(JRubyCallSite site, RubyClass cls, CacheEntry entry, int arity) { IndirectBindingException ibe; try { return tryDispatchDirect(site, cls, entry.method); } catch (IndirectBindingException _ibe) { ibe = _ibe; // proceed with indirect, if enabled } // if indirect indy-bound methods (via DynamicMethod.call) are disabled, bail out if (!RubyInstanceConfig.INVOKEDYNAMIC_INDIRECT) { if (RubyInstanceConfig.LOG_INDY_BINDINGS) LOG.info(site.name() + "\tfailed to bind to " + logMethod(entry.method) + ": " + ibe.getMessage()); return null; } // no direct native path, use DynamicMethod.call if (RubyInstanceConfig.LOG_INDY_BINDINGS) LOG.info(site.name() + "\tbound indirectly to " + logMethod(entry.method) + ": " + ibe.getMessage()); MethodHandle dynMethodTarget = getDynamicMethodTarget(site.type(), arity, entry.method); dynMethodTarget = insertArguments(dynMethodTarget, 4, site.name()); dynMethodTarget = insertArguments(dynMethodTarget, 0, entry.method); return dynMethodTarget; }
public static DynamicMethod unwrapMethod(DynamicMethod method, String[] realName) throws IndirectBindingException { // get the "real" method in a few ways while (method instanceof AliasMethod) { realName[0] = ((AliasMethod)method).getOldName(); // need to use original name, not aliased name method = method.getRealMethod(); } while (method instanceof WrapperMethod) method = method.getRealMethod(); // ProfilingDynamicMethod wraps any number of other types of methods but // we do not handle it in indy binding right now. Disable direct binding // and bind through DynamicMethod. if (method instanceof ProfilingDynamicMethod) { throw new IndirectBindingException("profiling active"); } if (method instanceof DefaultMethod) { DefaultMethod defaultMethod = (DefaultMethod) method; if (defaultMethod.getMethodForCaching() instanceof JittedMethod) { method = defaultMethod.getMethodForCaching(); } } return method; }
@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; } }
@Override public boolean canGenerate(JRubyCallSite site, RubyClass cls, DynamicMethod method) { NativeCall nativeCall = method.getNativeCall(); if (method instanceof CompiledMethod || method instanceof JittedMethod) { 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; }
@Override public boolean canGenerate(JRubyCallSite site, RubyClass cls, DynamicMethod method) { NativeCall nativeCall = method.getNativeCall(); if (method instanceof CompiledMethod || method instanceof JittedMethod) { 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; }
@Override public boolean canGenerate(JRubyCallSite site, RubyClass cls, DynamicMethod method) { if (method instanceof AttrWriterMethod) { // attr writer if (!RubyInstanceConfig.INVOKEDYNAMIC_ATTR) { throw new IndirectBindingException("direct attribute dispatch not enabled"); } if (site.arity() != 1) { throw new IndirectBindingException("attr writer with > 1 args"); } return true; } return false; }
@Override public boolean canGenerate(JRubyCallSite site, RubyClass cls, DynamicMethod method) { if (method instanceof AttrReaderMethod) { // attr reader if (!RubyInstanceConfig.INVOKEDYNAMIC_ATTR) { throw new IndirectBindingException("direct attribute dispatch not enabled"); } if (site.arity() != 0) { throw new IndirectBindingException("attr reader with > 0 args"); } return true; } return false; }
@Override public boolean canGenerate(JRubyCallSite site, RubyClass cls, DynamicMethod method) { if (method instanceof AttrReaderMethod) { // attr reader if (!RubyInstanceConfig.INVOKEDYNAMIC_ATTR) { throw new IndirectBindingException("direct attribute dispatch not enabled"); } if (site.arity() != 0) { throw new IndirectBindingException("attr reader with > 0 args"); } return true; } return false; }
@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; }
@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; } }
@Override public boolean canGenerate(JRubyCallSite site, RubyClass cls, DynamicMethod method) { if (method instanceof AttrWriterMethod) { // attr writer if (!RubyInstanceConfig.INVOKEDYNAMIC_ATTR) { throw new IndirectBindingException("direct attribute dispatch not enabled"); } if (site.arity() != 1) { throw new IndirectBindingException("attr writer with > 1 args"); } return true; } return false; }
private static MethodHandle tryDispatchDirect(JRubyCallSite site, RubyClass cls, DynamicMethod method) { String[] realName = {site.name()}; method = unwrapMethod(method, realName); for (HandleGenerator generator : HANDLE_GENERATORS) { if (generator.canGenerate(site, cls, method)) { return generator.generate(site, cls, method, realName[0]); } } throw new IndirectBindingException("no direct path available for " + method.getClass().getName()); }
@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; }