private static MethodHandle createFFIHandle(JRubyCallSite site, DynamicMethod method) { if (site.type().parameterType(site.type().parameterCount() - 1) == Block.class) { // Called with a block to substitute for a callback param - cannot cache or use a cached handle return null; } MethodHandle nativeTarget = (MethodHandle) method.getHandle(); if (nativeTarget != null) return nativeTarget; nativeTarget = org.jruby.ext.ffi.jffi.InvokeDynamic.getMethodHandle(site, method); if (nativeTarget != null) { method.setHandle(nativeTarget); return nativeTarget; } // can't build native handle for it return null; }
private static MethodHandle createFFIHandle(JRubyCallSite site, DynamicMethod method) { if (site.type().parameterType(site.type().parameterCount() - 1) == Block.class) { // Called with a block to substitute for a callback param - cannot cache or use a cached handle return null; } MethodHandle nativeTarget = (MethodHandle) method.getHandle(); if (nativeTarget != null) return nativeTarget; nativeTarget = org.jruby.ext.ffi.jffi.InvokeDynamic.getMethodHandle(site, method); if (nativeTarget != null) { method.setHandle(nativeTarget); return nativeTarget; } // can't build native handle for it return null; }
private static MethodHandle addOrRemoveBlock(JRubyCallSite site, MethodHandle nativeTarget) { // add NULL_BLOCK if needed if ( site.type().parameterCount() > 0 && site.type().parameterArray()[site.type().parameterCount() - 1] != Block.class && nativeTarget.type().parameterCount() > 0 && nativeTarget.type().parameterType(nativeTarget.type().parameterCount() - 1) == Block.class) { nativeTarget = insertArguments(nativeTarget, nativeTarget.type().parameterCount() - 1, Block.NULL_BLOCK); } else if ( site.type().parameterCount() > 0 && site.type().parameterArray()[site.type().parameterCount() - 1] == Block.class && nativeTarget.type().parameterCount() > 0 && nativeTarget.type().parameterType(nativeTarget.type().parameterCount() - 1) != Block.class) { // drop block if not used nativeTarget = dropArguments(nativeTarget, nativeTarget.type().parameterCount(), Block.class); } return nativeTarget; }
private static MethodHandle addOrRemoveBlock(JRubyCallSite site, MethodHandle nativeTarget) { // add NULL_BLOCK if needed if ( site.type().parameterCount() > 0 && site.type().parameterArray()[site.type().parameterCount() - 1] != Block.class && nativeTarget.type().parameterCount() > 0 && nativeTarget.type().parameterType(nativeTarget.type().parameterCount() - 1) == Block.class) { nativeTarget = insertArguments(nativeTarget, nativeTarget.type().parameterCount() - 1, Block.NULL_BLOCK); } else if ( site.type().parameterCount() > 0 && site.type().parameterArray()[site.type().parameterCount() - 1] == Block.class && nativeTarget.type().parameterCount() > 0 && nativeTarget.type().parameterType(nativeTarget.type().parameterCount() - 1) != Block.class) { // drop block if not used nativeTarget = dropArguments(nativeTarget, nativeTarget.type().parameterCount(), Block.class); } return nativeTarget; }
site.type().insertParameterTypes(0, JumpException.BreakJump.class), new int[] {0, 1}); .tryFinally(permuteArguments(BLOCK_ESCAPE, site.type().changeReturnType(void.class), site.type().parameterCount() - 1)) .invoke(target); if (site.type().parameterArray()[site.type().parameterCount() - 1] == IRubyObject[].class) { newTarget = filterArguments(newTarget, 0, findStatic(InvocationLinker.class, "getLast", methodType(IRubyObject.class, IRubyObject[].class)));
site.type().insertParameterTypes(0, JumpException.BreakJump.class), new int[] {0, 1}); .tryFinally(permuteArguments(BLOCK_ESCAPE, site.type().changeReturnType(void.class), site.type().parameterCount() - 1)) .invoke(target); if (site.type().parameterArray()[site.type().parameterCount() - 1] == IRubyObject[].class) { newTarget = filterArguments(newTarget, 0, findStatic(InvocationLinker.class, "getLast", methodType(IRubyObject.class, IRubyObject[].class)));
@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; }
.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");
return Binder.from(site.type().changeReturnType(boolean.class)) .drop(0, 3) .invoke(isTrue);
return Binder.from(site.type().changeReturnType(boolean.class)) .drop(0, 3) .invoke(isTrue);
.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");
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; }
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; }
MethodHandle methodHandle = Binder.from(site.type()) .drop(0, 3).invoke(targetHandle);
MethodHandle methodHandle = Binder.from(site.type()) .drop(0, 3).invoke(targetHandle);