Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  package org.jruby.ext.ffi.jffi;
  
  import org.jruby.Ruby;
 
 
 import static java.lang.invoke.MethodType.methodType;
 import static org.jruby.runtime.invokedynamic.InvokeDynamicSupport.findStatic;

 
 public final class InvokeDynamic {
     private static final Logger LOG = LoggerFactory.getLogger("ffi invokedynamic");
     private InvokeDynamic() {}
 
 
     private static final class IndyNotSupportedException extends Exception {
         private IndyNotSupportedException() {
         }
 
         private IndyNotSupportedException(String message) {
             super(message);
         }
     }
 
     public static MethodHandle getMethodHandle(JRubyCallSite siteDynamicMethod method) {
         try {
             MethodHandle fast = getFastNumericMethodHandle(sitemethod);
             if (fast == null) {
                 return generateNativeInvokerHandle(sitemethod);
             }
 
             MethodHandle guard = getDirectPointerParameterGuard(sitemethod);
             return guard != null
                 ? MethodHandles.guardWithTest(guardfastgenerateNativeInvokerHandle(sitemethod))
                 : fast;
         
         } catch (IndyNotSupportedException inse) {
             if (..load()) {
                 .info(site.name() + "\t" + inse.getLocalizedMessage());
             }
             return null;
 
         } catch (NullPointerException npe) {
             if (..load()) {
                 .info(site.name() + "\t" + npe.getLocalizedMessage());
             }
 
             return null;
         }
     }
 
     public static MethodHandle getFastNumericMethodHandle(JRubyCallSite siteDynamicMethod method) {
         Signature signature = (method instanceof NativeInvoker)
                 ? ((NativeInvokermethod).getSignature()
                 : ((DefaultMethodmethod).getSignature();
 
 
         CallContext callContext = (method instanceof NativeInvoker)
                 ? ((NativeInvokermethod).getCallContext()
                 : ((DefaultMethodmethod).getCallContext();
 
         long functionAddress = (method instanceof NativeInvoker)
                 ? ((NativeInvokermethod).getFunctionAddress()
                 : ((DefaultMethodmethod).getFunctionAddress();
 
         MethodHandle nativeInvoker;
         Method invokerMethod;
 
         com.kenai.jffi.InvokeDynamicSupport.Invoker jffiInvoker = com.kenai.jffi.InvokeDynamicSupport.getFastNumericInvoker(callContextfunctionAddress);
         if (jffiInvoker == null || jffiInvoker.getMethod() == null || !(jffiInvoker.getMethodHandle() instanceof MethodHandle)) {
             return null;
         }
 
         nativeInvoker = (MethodHandlejffiInvoker.getMethodHandle();
         invokerMethod = jffiInvoker.getMethod();
 
         Class nativeIntClass = invokerMethod.getReturnType();
        MethodHandle resultFilter = getResultFilter(method.getImplementationClass().getRuntime(), signature.getResultType().getNativeType(), nativeIntClass);
        if (resultFilter == null) {
            return null;
        }
        MethodHandle[] parameterFilters = getParameterFilters(signaturenativeIntClass);
        if (parameterFilters == null) {
            return null;
        }
        MethodHandle targetHandle = Binder.from(IRubyObject.class, CodegenUtils.params(IRubyObject.classsignature.getParameterCount()))
                .filter(0, parameterFilters)
                .filterReturn(resultFilter)
                .invoke(nativeInvoker);
        if (signature.getParameterCount() > 3) {
            // Expand the incoming IRubyObject[] parameter array to individual params
            targetHandle = targetHandle.asSpreader(IRubyObject[].classsignature.getParameterCount());
        }
        MethodHandle methodHandle = Binder.from(site.type())
                .drop(0, 3).invoke(targetHandle);
        if (..load()) .info(site.name()
                + "\tbound to ffi method "
                + logMethod(method)
                + String.format("[function address=%x]: "functionAddress)
                + invokerMethod);
        return methodHandle;
    }
        if (method instanceof org.jruby.ext.ffi.jffi.DefaultMethod) {
            NativeInvoker nativeInvoker = ((org.jruby.ext.ffi.jffi.DefaultMethodmethod).forceCompilation();
            if (nativeInvoker == null) {
                // Compilation failed, cannot build a native handle for it
                throw new IndyNotSupportedException("compilation failed");
            }
            method = nativeInvoker;
        }
        if (!method.getArity().isFixed()) {
            throw new IndyNotSupportedException("non fixed arity");
        }
        if (method.getArity().getValue() > 6) {
            throw new IndyNotSupportedException("arity > 6");
        }
        if (!..equals(method.getCallConfig())) {
            throw new IndyNotSupportedException("cannot bindy functions with scope or frame");
        }
        
        Class[] callMethodParameters = new Class[4 + method.getArity().getValue()];
        callMethodParameters[0] = ThreadContext.class;
        callMethodParameters[1] = IRubyObject.class;
        callMethodParameters[2] = RubyModule.class;
        callMethodParameters[3] = String.class;
        Arrays.fill(callMethodParameters, 4, callMethodParameters.lengthIRubyObject.class);
        MethodHandle nativeTarget;
        try {
            nativeTarget = site.lookup().findVirtual(method.getClass(), "call",
                    methodType(IRubyObject.classcallMethodParameters));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        int argCount = method.getArity().getValue();
        if (argCount > 3) {
            // Expand the incoming IRubyObject[] parameter array to individual params
            nativeTarget = nativeTarget.asSpreader(IRubyObject[].classargCount);
        }
        nativeTarget = Binder.from(site.type())
                .drop(1, 1)
                .insert(2, method.getImplementationClass(), site.name())
                .invoke(nativeTarget.bindTo(method));
        method.setHandle(nativeTarget);
        if (..load()) .info(site.name() + "\tbound to ffi method "
                + logMethod(method) + ": "
                + IRubyObject.class.getSimpleName() + " "
                + method.getClass().getSimpleName() + ".call"
                + CodegenUtils.prettyShortParams(callMethodParameters));
        return nativeTarget;
    }
    private static String logMethod(DynamicMethod method) {
        return "[#" + method.getSerialNumber() + " " + method.getImplementationClass() + "]";
    }
    private static MethodHandle findResultHelper(String nameClass nativeIntClass) {
        return findStatic(JITRuntime.classname, MethodType.methodType(IRubyObject.classRuby.classnativeIntClass));
    }
    private static MethodHandle getResultFilter(Ruby runtimeNativeType nativeTypeClass nativeIntClass) {
        MethodHandle resultFilter;
        switch (nativeType) {
            case :
                // just discard the int return value, and return nil
                return Binder.from(IRubyObject.classnativeIntClass).drop(0).constant(runtime.getNil());
            case :
                resultFilter = findResultHelper("newBoolean"nativeIntClass);
                break;
            case :
                resultFilter = findResultHelper("newSigned8"nativeIntClass);
                break;
            case :
                resultFilter = findResultHelper("newUnsigned8"nativeIntClass);
                break;
            case :
                resultFilter = findResultHelper("newSigned16"nativeIntClass);
                break;
            case :
                resultFilter = findResultHelper("newUnsigned16"nativeIntClass);
                break;
            case :
                resultFilter = findResultHelper("newSigned32"nativeIntClass);
                break;
            case :
                resultFilter = findResultHelper("newUnsigned32"nativeIntClass);
                break;
            case :
                resultFilter = findResultHelper("newSigned" + Platform.getPlatform().longSize(), nativeIntClass);
                break;
            case :
                resultFilter = findResultHelper("newUnsigned" + Platform.getPlatform().longSize(), nativeIntClass);
                break;
            case :
                resultFilter = findResultHelper("newSigned64"nativeIntClass);
                break;
            case :
                resultFilter = findResultHelper("newUnsigned64"nativeIntClass);
                break;
            case :
                resultFilter = findResultHelper("newFloat32"nativeIntClass);
                break;
            case :
                resultFilter = findResultHelper("newFloat64"nativeIntClass);
                break;
            case :
                resultFilter = findResultHelper("newPointer" + Platform.getPlatform().addressSize(), nativeIntClass);
                break;
            case :
            case :
                resultFilter = findResultHelper("newString"nativeIntClass);
                break;
            default:
                return null;
        }
        return MethodHandles.insertArguments(resultFilter, 0, runtime);
    }
    private static MethodHandle findParameterHelper(String nameClass nativeIntClass) {
        return findStatic(JITRuntime.classname + (int.class == nativeIntClass ? 32 : 64),
                MethodType.methodType(nativeIntClassIRubyObject.class));
    }
    private static MethodHandle[] getParameterFilters(Signature signatureClass nativeIntClass) {
        MethodHandle[] parameterFilters = new MethodHandle[signature.getParameterCount()];
        for (int i = 0; i < signature.getParameterCount(); i++) {
            if (!(signature.getParameterType(iinstanceof Type.Builtin)) {
                return null;
            }
            MethodHandle ph;
            switch (signature.getParameterType(i).getNativeType()) {
                case :
                    ph = findParameterHelper("boolValue"nativeIntClass);
                    break;
                case :
                    ph = findParameterHelper("s8Value"nativeIntClass);
                    break;
                case :
                    ph = findParameterHelper("u8Value"nativeIntClass);
                    break;
                case :
                    ph = findParameterHelper("s16Value"nativeIntClass);
                    break;
                case :
                    ph = findParameterHelper("u16Value"nativeIntClass);
                    break;
                case :
                    ph = findParameterHelper("s32Value"nativeIntClass);
                    break;
                case :
                    ph = findParameterHelper("u32Value"nativeIntClass);
                    break;
                case :
                    ph = findParameterHelper("s" + Platform.getPlatform().longSize() + "Value"nativeIntClass);
                    break;
                case :
                    ph = findParameterHelper("u" + Platform.getPlatform().longSize() + "Value"nativeIntClass);
                    break;
                case :
                    ph = findParameterHelper("s64Value"nativeIntClass);
                    break;
                case :
                    ph = findParameterHelper("u64Value"nativeIntClass);
                    break;
                case :
                    ph = findParameterHelper("f32Value"nativeIntClass);
                    break;
                case :
                    ph = findParameterHelper("f64Value"nativeIntClass);
                    break;
                case :
                case :
                case :
                case :
                    ph = findParameterHelper("pointerValue"nativeIntClass);
                    break;
                default:
                    return null;
            }
            parameterFilters[i] = ph;
        }
        return parameterFilters;
    }
    private static MethodHandle getDirectPointerParameterGuard(JRubyCallSite siteDynamicMethod method) {
        Signature signature = (method instanceof NativeInvoker)
                ? ((NativeInvokermethod).getSignature()
                : ((DefaultMethodmethod).getSignature();
        MethodHandle[] guards = new MethodHandle[signature.getParameterCount()];
        Arrays.fill(guards, 0, guards.length, Binder.from(boolean.classIRubyObject.class).drop(0, 1).constant(true));
        boolean guardNeeded = false;
        for (int i = 0; i < signature.getParameterCount(); i++) {
            switch (signature.getParameterType(i).getNativeType()) {
                case :
                case :
                case :
                case :
                    guards[i] = findStatic(JITRuntime.class"isDirectPointer", MethodType.methodType(boolean.classIRubyObject.class));
                    guardNeeded = true;
                    break;
            }
        }
        if (!guardNeeded) {
            return null;
        }
        MethodHandle isTrue = findStatic(JITRuntime.class"isTrue",
                methodType(boolean.class, CodegenUtils.params(boolean.classsignature.getParameterCount())));
        isTrue = Binder.from(boolean.class, CodegenUtils.params(IRubyObject.classsignature.getParameterCount()))
                .filter(0, guards)
                .invoke(isTrue);
        if (signature.getParameterCount() > 3) {
            // Expand the incoming IRubyObject[] parameter array to individual params
            isTrue = isTrue.asSpreader(IRubyObject[].classsignature.getParameterCount());
        }
        return Binder.from(site.type().changeReturnType(boolean.class))
                .drop(0, 3)
                .invoke(isTrue);
    }
New to GrepCode? Check out our FAQ X