package org.jruby.ext.ffi.jffi;
import com.kenai.jffi.*;
import org.jruby.Ruby;
import org.jruby.RubyModule;
import org.jruby.ext.ffi.*;
import org.jruby.ext.ffi.NativeType;
import org.jruby.ext.ffi.Type;
import org.jruby.internal.runtime.methods.DynamicMethod;
import org.jruby.runtime.Arity;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.callsite.CachingCallSite;
import org.jruby.runtime.callsite.FunctionalCachingCallSite;
import org.jruby.util.cli.Options;
import java.util.Arrays;
abstract public class JITNativeInvoker extends NativeInvoker {
protected static final Invoker invoker = Invoker.getInstance();
protected final com.kenai.jffi.Function function;
protected final com.kenai.jffi.CallContext callContext;
protected final long functionAddress;
protected final Signature signature;
protected final int arity;
protected final NativeDataConverter resultConverter;
protected final NativeDataConverter parameterConverter0;
protected final NativeDataConverter parameterConverter1;
protected final NativeDataConverter parameterConverter2;
protected final NativeDataConverter parameterConverter3;
protected final NativeDataConverter parameterConverter4;
protected final NativeDataConverter parameterConverter5;
protected final ObjectParameterInfo parameterInfo0;
protected final ObjectParameterInfo parameterInfo1;
protected final ObjectParameterInfo parameterInfo2;
protected final ObjectParameterInfo parameterInfo3;
protected final ObjectParameterInfo parameterInfo4;
protected final ObjectParameterInfo parameterInfo5;
protected final CachingCallSite parameterCallSite0;
protected final CachingCallSite parameterCallSite1;
protected final CachingCallSite parameterCallSite2;
protected final CachingCallSite parameterCallSite3;
protected final CachingCallSite parameterCallSite4;
protected final CachingCallSite parameterCallSite5;
protected final CachingCallSite parameterCallSite6;
public JITNativeInvoker(RubyModule implementationClass, com.kenai.jffi.Function function, Signature signature) {
super(implementationClass, function, signature);
this.arity = signature.getParameterCount();
this.function = function;
this.callContext = function.getCallContext();
this.functionAddress = function.getFunctionAddress();
this.signature = signature;
resultConverter = DataConverters.getResultConverter(signature.getResultType());
parameterConverter0 = getParameterConverter(signature, 0);
parameterConverter1 = getParameterConverter(signature, 1);
parameterConverter2 = getParameterConverter(signature, 2);
parameterConverter3 = getParameterConverter(signature, 3);
parameterConverter4 = getParameterConverter(signature, 4);
parameterConverter5 = getParameterConverter(signature, 5);
parameterInfo0 = getParameterInfo(signature, 0);
parameterInfo1 = getParameterInfo(signature, 1);
parameterInfo2 = getParameterInfo(signature, 2);
parameterInfo3 = getParameterInfo(signature, 3);
parameterInfo4 = getParameterInfo(signature, 4);
parameterInfo5 = getParameterInfo(signature, 5);
parameterCallSite0 = getParameterCallSite(signature, 0);
parameterCallSite1 = getParameterCallSite(signature, 1);
parameterCallSite2 = getParameterCallSite(signature, 2);
parameterCallSite3 = getParameterCallSite(signature, 3);
parameterCallSite4 = getParameterCallSite(signature, 4);
parameterCallSite5 = getParameterCallSite(signature, 5);
parameterCallSite6 = getParameterCallSite(signature, 6);
}
@SuppressWarnings("deprecation")
private static NativeDataConverter getParameterConverter(Signature signature, int i) {
return signature.getParameterCount() > i
? DataConverters.getParameterConverter(signature.getParameterType(i), signature.getEnums()) : null;
}
private static ObjectParameterInfo getParameterInfo(Signature signature, int i) {
if (signature.getParameterCount() <= i) {
return null;
}
Type type = signature.getParameterType(i);
int flags = 0;
NativeType nativeType = type instanceof MappedType
? ((MappedType) type).getRealType().getNativeType() : type.getNativeType();
switch (nativeType) {
case BUFFER_IN:
case STRING:
case TRANSIENT_STRING:
flags |= ObjectParameterInfo.IN | ObjectParameterInfo.NULTERMINATE;
break;
case BUFFER_OUT:
flags |= ObjectParameterInfo.OUT | ObjectParameterInfo.CLEAR;
break;
case POINTER:
case BUFFER_INOUT:
flags |= ObjectParameterInfo.IN | ObjectParameterInfo.OUT | ObjectParameterInfo.CLEAR | ObjectParameterInfo.NULTERMINATE;
break;
default:
return null;
}
return ObjectParameterInfo.create(i, ObjectParameterInfo.ARRAY, ObjectParameterInfo.BYTE, flags);
}
private static CachingCallSite getParameterCallSite(Signature signature, int parameterIndex) {
if (signature.getParameterCount() <= parameterIndex) {
return null;
}
Type type = signature.getParameterType(parameterIndex);
NativeType nativeType = type instanceof MappedType
? ((MappedType) type).getRealType().getNativeType() : type.getNativeType();
switch (nativeType) {
case STRING:
case TRANSIENT_STRING:
return new FunctionalCachingCallSite("to_str");
case POINTER:
case BUFFER_IN:
case BUFFER_OUT:
case BUFFER_INOUT:
return new FunctionalCachingCallSite("to_ptr");
default:
return null;
}
}
Signature getSignature() {
return signature;
}
CallContext getCallContext() {
return callContext;
}
long getFunctionAddress() {
return functionAddress;
}
@Override
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule klazz, String name) {
throw context.runtime.newArgumentError(0, arity);
}
@Override
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule klazz, String name,
IRubyObject arg1) {
throw context.runtime.newArgumentError(1, arity);
}
@Override
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule klazz, String name,
IRubyObject arg1, IRubyObject arg2) {
throw context.runtime.newArgumentError(2, arity);
}
@Override
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule klazz, String name,
IRubyObject arg1, IRubyObject arg2, IRubyObject arg3) {
throw context.runtime.newArgumentError(3, arity);
}
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule klazz, String name,
IRubyObject arg1, IRubyObject arg2, IRubyObject arg3, IRubyObject arg4) {
throw context.runtime.newArgumentError(4, arity);
}
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule klazz, String name,
IRubyObject arg1, IRubyObject arg2, IRubyObject arg3, IRubyObject arg4, IRubyObject arg5) {
throw context.runtime.newArgumentError(5, arity);
}
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule klazz, String name,
IRubyObject arg1, IRubyObject arg2, IRubyObject arg3, IRubyObject arg4,
IRubyObject arg5, IRubyObject arg6) {
throw context.runtime.newArgumentError(6, arity);
}
@Override
public final IRubyObject call(ThreadContext context, IRubyObject self,
RubyModule clazz, String name, IRubyObject[] args) {
if (args.length != arity) {
throw context.runtime.newArgumentError(args.length, arity);
}
switch (args.length) {
case 0:
return call(context, self, clazz, name);
case 1:
return call(context, self, clazz, name, args[0]);
case 2:
return call(context, self, clazz, name, args[0], args[1]);
case 3:
return call(context, self, clazz, name, args[0], args[1], args[2]);
case 4:
return call(context, self, clazz, name, args[0], args[1], args[2], args[3]);
case 5:
return call(context, self, clazz, name, args[0], args[1], args[2], args[3], args[4]);
case 6:
return call(context, self, clazz, name, args[0], args[1], args[2], args[3], args[4], args[5]);
default:
throw context.runtime.newArgumentError("too many arguments: " + args.length);
}
}
}