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() {}
 
 
     public static MethodHandle getMethodHandle(JRubyCallSite siteDynamicMethod method) {
         MethodHandle fast = getFastNumericMethodHandle(sitemethod);
         if (fast == null) {
             return generateNativeInvokerHandle(sitemethod);
         }
 
         MethodHandle guard = getDirectPointerParameterGuard(sitemethod);
         return guard != null
             ? MethodHandles.guardWithTest(guardfastgenerateNativeInvokerHandle(sitemethod))
             : fast;
     }
 
     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);
         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 (..info(site.name()
                 + "\tbound to ffi method "
                 + logMethod(method)
                 + String.format("[function address=%x]: "functionAddress)
                 + invokerMethod);
        return methodHandle;
    }
    private static MethodHandle generateNativeInvokerHandle(JRubyCallSite siteDynamicMethod method) {
        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
                return null;
            }
            method = nativeInvoker;
        }
        if (method.getArity().isFixed() && method.getArity().getValue() <= 6 && method.getCallConfig() == .) {
            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 (..info(site.name() + "\tbound to ffi method "
                    + logMethod(method) + ": "
                    + IRubyObject.class.getSimpleName() + " "
                    + method.getClass().getSimpleName() + ".call"
                    + CodegenUtils.prettyShortParams(callMethodParameters));
            return nativeTarget;
        }
        // can't build native handle for it
        return null;
    }
    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