src.org.python.modules.jffi.FastIntInvokerFactory Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jython-standalone Show documentation
Show all versions of jython-standalone Show documentation
Jython is an implementation of the high-level, dynamic, object-oriented
language Python written in 100% Pure Java, and seamlessly integrated with
the Java platform. It thus allows you to run Python on any Java platform.
package org.python.modules.jffi;
import com.kenai.jffi.Function;
import com.kenai.jffi.Platform;
import org.python.core.Py;
import org.python.core.PyObject;
/**
* A factory which generates {@link Invoker} instances that are optimized for
* 32 bit integer and float parameters / result types with 3 or less parameters.
*
* Technical background: Instead of trying to cram all calls down a generic call
* path, then figuring out how to convert the parameters in the native code on
* each call, jffi supplies arity and type specific call paths that can be
* optimized ahead of time by the native code.
*
* The downside of this approach is more java code to wire up the functions and
* call them using the arity+type specific paths, but in the case of int and float
* parameters, it can result in more than a 100% speed boost over the generic path.
*/
public class FastIntInvokerFactory {
private static final class SingletonHolder {
private static final FastIntInvokerFactory INSTANCE = new FastIntInvokerFactory();
}
private FastIntInvokerFactory() {}
public static final FastIntInvokerFactory getFactory() {
return SingletonHolder.INSTANCE;
}
/**
* Interface used to convert from a python object to a native integer
*/
private static interface IntParameterConverter {
int intValue(PyObject value);
}
/**
* Interface used to convert from a native integer to a python object
*/
private static interface IntResultConverter {
PyObject pyValue(int value);
}
/**
* Tests if a combination of result and parameter types can be called using
* an {@link Invoker} created by this factory.
*
* @param returnType The return type of the native function.
* @param parameterTypes The parameter types of the native function.
* @return true if the method can be handled as a fast int method.
*/
final boolean isFastIntMethod(CType returnType, CType[] parameterTypes) {
for (int i = 0; i < parameterTypes.length; ++i) {
if (!isFastIntParam(parameterTypes[i])) {
return false;
}
}
return parameterTypes.length <= 3 && isFastIntResult(returnType);
}
/**
* Tests if a combination of result and parameter types can be called using
* an {@link Invoker} created by this factory.
*
* @param returnType The return type of the native function.
* @param parameterTypes The parameter types of the native function.
* @return true if the method can be handled as a fast int method.
*/
final boolean isFastIntMethod(PyObject returnType, PyObject[] parameterTypes) {
for (int i = 0; i < parameterTypes.length; ++i) {
if (!isFastIntParam(parameterTypes[i])) {
return false;
}
}
return parameterTypes.length <= 3 && isFastIntResult(returnType);
}
/**
* Tests if the type can be returned as an integer result.
*
* @param type The result type.
* @return true if type can be returned as an integer.
*/
final boolean isFastIntResult(CType type) {
if (type instanceof CType.Builtin) {
switch (type.getNativeType()) {
case VOID:
case BYTE:
case UBYTE:
case SHORT:
case USHORT:
case INT:
case UINT:
return true;
case LONG:
case ULONG:
return Platform.getPlatform().longSize() == 32;
case STRING:
return Platform.getPlatform().addressSize() == 32;
}
}
return false;
}
/**
* Tests if the type can be returned as an integer result.
*
* @param type The result type.
* @return true if type can be returned as an integer.
*/
final boolean isFastIntResult(PyObject type) {
return isFastIntResult(CType.typeOf(type));
}
/**
* Tests if the type can be passed as an integer parameter.
*
* @param type The parameter type.
* @return true if type can be passed as an integer.
*/
final boolean isFastIntParam(CType paramType) {
if (paramType instanceof CType.Builtin) {
switch (paramType.getNativeType()) {
case BYTE:
case UBYTE:
case SHORT:
case USHORT:
case INT:
case UINT:
return true;
case LONG:
case ULONG:
return Platform.getPlatform().longSize() == 32;
}
}
return false;
}
/**
* Tests if the type can be passed as an integer parameter.
*
* @param type The parameter type.
* @return true if type can be passed as an integer.
*/
final boolean isFastIntParam(PyObject paramType) {
return isFastIntParam(CType.typeOf(paramType));
}
/**
* Creates a new Invoker instance for the given function, with the
* given parameter types and return type.
*
* @param function The JFFI function to wrap
* @param parameterTypes The parameter types the function will be called with
* @param returnType The result type the function will return
* @return A new {@link Invoker} instance.
*/
final Invoker createInvoker(Function function, CType[] parameterTypes, CType returnType) {
IntParameterConverter[] parameterConverters = new IntParameterConverter[parameterTypes.length];
for (int i = 0; i < parameterConverters.length; ++i) {
parameterConverters[i] = getIntParameterConverter(parameterTypes[i]);
}
return createIntInvoker(function, getIntResultConverter(returnType), parameterConverters);
}
/**
* Creates a new Invoker instance for the given function, with the
* given parameter types and return type.
*
* @param function The JFFI function to wrap
* @param parameterTypes The parameter types the function will be called with
* @param returnType The result type the function will return
* @return A new {@link Invoker} instance.
*/
final Invoker createInvoker(Function function, PyObject returnType, PyObject[] parameterTypes) {
IntParameterConverter[] parameterConverters = new IntParameterConverter[parameterTypes.length];
for (int i = 0; i < parameterConverters.length; ++i) {
parameterConverters[i] = getIntParameterConverter(parameterTypes[i]);
}
return createIntInvoker(function, getIntResultConverter(returnType), parameterConverters);
}
final Invoker createIntInvoker(Function function, IntResultConverter resultConverter, IntParameterConverter[] parameterConverters) {
switch (parameterConverters.length) {
case 0:
return new FastIntInvokerZero(function, resultConverter, parameterConverters);
case 1:
return new FastIntInvokerOne(function, resultConverter, parameterConverters);
case 2:
return new FastIntInvokerTwo(function, resultConverter, parameterConverters);
case 3:
return new FastIntInvokerThree(function, resultConverter, parameterConverters);
}
throw Py.RuntimeError("fast int invoker does not support functions with arity=" + parameterConverters.length);
}
/**
* Gets a python object to integer parameter converter.
*
* @param type The python C type
* @return An IntParameterConverter instance.
*/
final IntParameterConverter getIntParameterConverter(CType type) {
if (type instanceof CType.Builtin) {
return getIntParameterConverter(type.getNativeType());
}
throw Py.TypeError("cannot convert objects of type " + type + " to int");
}
/**
* Gets a python object to integer parameter converter.
*
* @param type The python C type
* @return An IntParameterConverter instance.
*/
final IntParameterConverter getIntParameterConverter(PyObject type) {
return getIntParameterConverter(CType.typeOf(type));
}
/**
* Gets a python object to integer parameter converter.
*
* @param type The object type.
* @return An IntParameterConverter instance.
*/
final IntParameterConverter getIntParameterConverter(NativeType type) {
switch (type) {
case BYTE:
return Signed8ParameterConverter.INSTANCE;
case UBYTE:
return Unsigned8ParameterConverter.INSTANCE;
case SHORT:
return Signed16ParameterConverter.INSTANCE;
case USHORT:
return Unsigned16ParameterConverter.INSTANCE;
case INT:
return Signed32ParameterConverter.INSTANCE;
case UINT:
return Unsigned32ParameterConverter.INSTANCE;
case LONG:
if (Platform.getPlatform().longSize() == 32) {
return Signed32ParameterConverter.INSTANCE;
}
break;
case ULONG:
if (Platform.getPlatform().longSize() == 32) {
return Unsigned32ParameterConverter.INSTANCE;
}
break;
case FLOAT:
if (Platform.getPlatform().getCPU() == Platform.CPU.I386
|| Platform.getPlatform().getCPU() == Platform.CPU.X86_64) {
return Float32ParameterConverter.INSTANCE;
}
break;
default:
break;
}
throw Py.TypeError("cannot convert objects of type " + type + " to int");
}
/**
* Gets a int to python object result converter for the type.
*
* @param type The object type.
* @return An IntResultConverter instance.
*/
final IntResultConverter getIntResultConverter(PyObject type) {
return getIntResultConverter(CType.typeOf(type));
}
/**
* Gets a int to python object result converter for the type.
*
* @param type The object type.
* @return An IntResultConverter instance.
*/
final IntResultConverter getIntResultConverter(CType type) {
return type instanceof CType.Builtin ? getIntResultConverter(type.getNativeType()) : null;
}
/**
* Gets a int to python object result converter for the type.
*
* @param type The object type.
* @return An IntResultConverter instance.
*/
final IntResultConverter getIntResultConverter(NativeType type) {
switch (type) {
case VOID:
return VoidResultConverter.INSTANCE;
case BYTE:
return Signed8ResultConverter.INSTANCE;
case UBYTE:
return Unsigned8ResultConverter.INSTANCE;
case SHORT:
return Signed16ResultConverter.INSTANCE;
case USHORT:
return Unsigned16ResultConverter.INSTANCE;
case INT:
return Signed32ResultConverter.INSTANCE;
case UINT:
return Unsigned32ResultConverter.INSTANCE;
case LONG:
if (Platform.getPlatform().longSize() == 32) {
return Signed32ResultConverter.INSTANCE;
}
break;
case ULONG:
if (Platform.getPlatform().longSize() == 32) {
return Unsigned32ResultConverter.INSTANCE;
}
break;
case STRING:
if (Platform.getPlatform().addressSize() == 32) {
return StringResultConverter.INSTANCE;
}
break;
default:
break;
}
throw new IllegalArgumentException("Cannot convert objects of type " + type + " from int");
}
/**
* Base class for all fast-int {@link Invoker} subclasses
*/
private static abstract class BaseFastIntInvoker implements Invoker {
final com.kenai.jffi.Invoker jffiInvoker = com.kenai.jffi.Invoker.getInstance();
final Function function;
final IntResultConverter resultConverter;
final int arity;
final IntParameterConverter c0, c1, c2;
BaseFastIntInvoker(Function function, IntResultConverter resultConverter,
IntParameterConverter[] parameterConverters) {
this.function = function;
this.resultConverter = resultConverter;
this.arity = parameterConverters.length;
c0 = parameterConverters.length > 0 ? parameterConverters[0] : null;
c1 = parameterConverters.length > 1 ? parameterConverters[1] : null;
c2 = parameterConverters.length > 2 ? parameterConverters[2] : null;
}
final void checkArity(PyObject[] args) {
checkArity(args.length);
}
final void checkArity(int got) {
if (got != arity) {
throw Py.TypeError(String.format("__call__() takes exactly %d arguments (%d given)", arity, got));
}
}
public PyObject invoke(PyObject[] args) {
checkArity(args);
switch (arity) {
case 0:
return invoke();
case 1:
return invoke(args[0]);
case 2:
return invoke(args[0], args[1]);
case 3:
return invoke(args[0], args[1], args[2]);
default:
throw Py.RuntimeError("invalid fast-int arity");
}
}
public PyObject invoke() {
checkArity(0);
return Py.None;
}
public PyObject invoke(PyObject arg1) {
checkArity(1);
return Py.None;
}
public PyObject invoke(PyObject arg1, PyObject arg2) {
checkArity(2);
return Py.None;
}
public PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3) {
checkArity(3);
return Py.None;
}
}
/**
* Fast-int invoker that takes no parameters.
*/
private static final class FastIntInvokerZero extends BaseFastIntInvoker {
public FastIntInvokerZero(Function function, IntResultConverter resultConverter,
IntParameterConverter parameterConverters[]) {
super(function, resultConverter, parameterConverters);
}
@Override
public final PyObject invoke() {
return resultConverter.pyValue(jffiInvoker.invokeVrI(function));
}
}
/**
* Fast-int invoker that takes a single parameter
*/
private static final class FastIntInvokerOne extends BaseFastIntInvoker {
public FastIntInvokerOne(Function function, IntResultConverter resultConverter,
IntParameterConverter parameterConverters[]) {
super(function, resultConverter, parameterConverters);
}
@Override
public final PyObject invoke(PyObject arg0) {
return resultConverter.pyValue(jffiInvoker.invokeIrI(function,
c0.intValue(arg0)));
}
}
/**
* Fast-int invoker that takes two parameters
*/
private static final class FastIntInvokerTwo extends BaseFastIntInvoker {
public FastIntInvokerTwo(Function function, IntResultConverter resultConverter,
IntParameterConverter parameterConverters[]) {
super(function, resultConverter, parameterConverters);
}
@Override
public PyObject invoke(PyObject arg0, PyObject arg1) {
return resultConverter.pyValue(jffiInvoker.invokeIIrI(function,
c0.intValue(arg0), c1.intValue(arg1)));
}
}
/**
* Fast-int invoker that takes three parameters
*/
private static final class FastIntInvokerThree extends BaseFastIntInvoker {
public FastIntInvokerThree(Function function, IntResultConverter resultConverter,
IntParameterConverter parameterConverters[]) {
super(function, resultConverter, parameterConverters);
}
@Override
public PyObject invoke(PyObject arg0, PyObject arg1, PyObject arg2) {
return resultConverter.pyValue(jffiInvoker.invokeIIIrI(function,
c0.intValue(arg0), c1.intValue(arg1), c2.intValue(arg2)));
}
}
/**
* Base class for all fast-int result converters
*/
static abstract class BaseResultConverter implements IntResultConverter {
}
/**
* Converts a native void result into into a python None instance
*/
static final class VoidResultConverter extends BaseResultConverter {
public static final IntResultConverter INSTANCE = new VoidResultConverter();
public final PyObject pyValue(int value) {
return Py.None;
}
}
/**
* Converts a native signed byte result into into a python integer instance
*/
static final class Signed8ResultConverter extends BaseResultConverter {
public static final IntResultConverter INSTANCE = new Signed8ResultConverter();
public final PyObject pyValue(int value) {
return Util.newSigned8(value);
}
}
/**
* Converts a native unsigned byte result into into a python integer instance
*/
static final class Unsigned8ResultConverter extends BaseResultConverter {
public static final IntResultConverter INSTANCE = new Unsigned8ResultConverter();
public final PyObject pyValue(int value) {
return Util.newUnsigned8(value);
}
}
/**
* Converts a native signed short result into into a python integer instance
*/
static final class Signed16ResultConverter extends BaseResultConverter {
public static final IntResultConverter INSTANCE = new Signed16ResultConverter();
public final PyObject pyValue(int value) {
return Util.newSigned16(value);
}
}
/**
* Converts a native unsigned short result into into a python integer instance
*/
static final class Unsigned16ResultConverter extends BaseResultConverter {
public static final IntResultConverter INSTANCE = new Unsigned16ResultConverter();
public final PyObject pyValue(int value) {
return Util.newUnsigned16(value);
}
}
/**
* Converts a native signed int result into into a python integer instance
*/
static final class Signed32ResultConverter extends BaseResultConverter {
public static final IntResultConverter INSTANCE = new Signed32ResultConverter();
public final PyObject pyValue(int value) {
return Util.newSigned32(value);
}
}
/**
* Converts a native unsigned int result into into a python integer instance
*/
static final class Unsigned32ResultConverter extends BaseResultConverter {
public static final IntResultConverter INSTANCE = new Unsigned32ResultConverter();
public final PyObject pyValue(int value) {
return Util.newUnsigned32(value);
}
}
/**
* Converts a native string address result into into a python string instance
*/
static final class StringResultConverter extends BaseResultConverter {
public static final IntResultConverter INSTANCE = new StringResultConverter();
public final PyObject pyValue(int value) {
return Util.newString(value);
}
}
/**
* Base class for all integer parameter converters.
*/
static abstract class BaseParameterConverter implements IntParameterConverter {
}
/**
* Converter for python signed byte to native int
*/
static final class Signed8ParameterConverter extends BaseParameterConverter {
public static final IntParameterConverter INSTANCE = new Signed8ParameterConverter();
public final int intValue(PyObject obj) {
return Util.int8Value(obj);
}
}
/**
* Converter for python unsigned byte to native int
*/
static final class Unsigned8ParameterConverter extends BaseParameterConverter {
public static final IntParameterConverter INSTANCE = new Unsigned8ParameterConverter();
public final int intValue(PyObject obj) {
return Util.uint8Value(obj);
}
}
/**
* Converter for python signed short to native int
*/
static final class Signed16ParameterConverter extends BaseParameterConverter {
public static final IntParameterConverter INSTANCE = new Signed16ParameterConverter();
public final int intValue(PyObject obj) {
return Util.int16Value(obj);
}
}
/**
* Converter for python unsigned short to native int
*/
static final class Unsigned16ParameterConverter extends BaseParameterConverter {
public static final IntParameterConverter INSTANCE = new Unsigned16ParameterConverter();
public final int intValue(PyObject obj) {
return Util.uint16Value(obj);
}
}
/**
* Converter for python signed int to native int
*/
static final class Signed32ParameterConverter extends BaseParameterConverter {
public static final IntParameterConverter INSTANCE = new Signed32ParameterConverter();
public final int intValue(PyObject obj) {
return Util.int32Value(obj);
}
}
/**
* Converter for python unsigned int to native int
*/
static final class Unsigned32ParameterConverter extends BaseParameterConverter {
public static final IntParameterConverter INSTANCE = new Unsigned32ParameterConverter();
public final int intValue(PyObject obj) {
return Util.uint32Value(obj);
}
}
/**
* Converter for python float to native int parameter
*/
static final class Float32ParameterConverter extends BaseParameterConverter {
public static final IntParameterConverter INSTANCE = new Float32ParameterConverter();
public final int intValue(PyObject obj) {
return Float.floatToIntBits((float) obj.asDouble());
}
}
}