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()); }
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; }