Beispiel #1
0
 public static int getNativeArgCount(DynamicMethod method, DynamicMethod.NativeCall nativeCall) {
   // if non-Java, must:
   // * exactly match arities or both are [] boxed
   // * 3 or fewer arguments
   return getArgCount(nativeCall.getNativeSignature(), nativeCall.isStatic());
 }
Beispiel #2
0
  static MethodHandle buildNativeHandle(InvokeSite site, DynamicMethod method, boolean blockGiven) {
    MethodHandle mh = null;
    SmartBinder binder = null;

    if (method.getNativeCall() != null) {

      int nativeArgCount = getNativeArgCount(method, method.getNativeCall());

      DynamicMethod.NativeCall nc = method.getNativeCall();

      if (nc.isJava()) {
        // not supported yet, use DynamicMethod.call
      } else {
        if (nativeArgCount >= 0) { // native methods only support arity 3
          if (nativeArgCount == site.arity) {
            // nothing to do
            binder = SmartBinder.from(lookup(), site.signature);
          } else {
            // arity mismatch...leave null and use DynamicMethod.call below
          }
        } else {
          // varargs
          if (site.arity == -1) {
            // ok, already passing []
            binder = SmartBinder.from(lookup(), site.signature);
          } else if (site.arity == 0) {
            // no args, insert dummy
            binder =
                SmartBinder.from(lookup(), site.signature)
                    .insert(2, "args", IRubyObject.NULL_ARRAY);
          } else {
            // 1 or more args, collect into []
            binder = SmartBinder.from(lookup(), site.signature).collect("args", "arg.*");
          }
        }

        if (binder != null) {

          // clean up non-arguments, ordering, types
          if (!nc.hasContext()) {
            binder = binder.drop("context");
          }

          if (nc.hasBlock() && !blockGiven) {
            binder = binder.append("block", Block.NULL_BLOCK);
          } else if (!nc.hasBlock() && blockGiven) {
            binder = binder.drop("block");
          }

          if (nc.isStatic()) {
            mh =
                binder
                    .permute("context", "self", "arg.*", "block") // filter caller
                    .cast(nc.getNativeReturn(), nc.getNativeSignature())
                    .invokeStaticQuiet(LOOKUP, nc.getNativeTarget(), nc.getNativeName())
                    .handle();
          } else {
            mh =
                binder
                    .permute("self", "context", "arg.*", "block") // filter caller, move self
                    .castArg("self", nc.getNativeTarget())
                    .castVirtual(
                        nc.getNativeReturn(), nc.getNativeTarget(), nc.getNativeSignature())
                    .invokeVirtualQuiet(LOOKUP, nc.getNativeName())
                    .handle();
          }
        }
      }
    }

    return mh;
  }