src.org.python.modules.jffi.AbstractNumericMethodGenerator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jython Show documentation
Show all versions of jython 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.Platform;
import org.objectweb.asm.Label;
import org.python.core.PyObject;
import static org.python.modules.jffi.CodegenUtils.*;
import static org.objectweb.asm.Opcodes.ACC_FINAL;
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
/**
*
*/
abstract class AbstractNumericMethodGenerator implements JITMethodGenerator {
public void generate(AsmClassBuilder builder, String functionName, JITSignature signature) {
SkinnyMethodAdapter mv = new SkinnyMethodAdapter(builder.getClassVisitor(),
ACC_PUBLIC | ACC_FINAL, functionName,
sig(PyObject.class, params(PyObject.class, signature.getParameterCount())),
null, null);
mv.start();
generate(builder, mv, signature);
mv.visitMaxs(10, 10);
mv.visitEnd();
}
public void generate(AsmClassBuilder builder, SkinnyMethodAdapter mv, JITSignature signature) {
final Class nativeIntType = getInvokerIntType();
int maxPointerIndex = -1;
Label[] fallback = new Label[signature.getParameterCount()];
for (int i = 0; i < signature.getParameterCount(); i++) {
fallback[i] = new Label();
}
mv.getstatic(p(JITInvoker.class), "jffiInvoker", ci(com.kenai.jffi.Invoker.class));
// [ stack now contains: Invoker ]
mv.aload(0);
mv.getfield(p(JITInvoker.class), "jffiFunction", ci(com.kenai.jffi.Function.class));
// [ stack now contains: Invoker, Function ]
final int firstParam = 1;
// Perform any generic data conversions on the parameters
for (int i = 0; i < signature.getParameterCount(); ++i) {
if (signature.hasParameterConverter(i)) {
mv.aload(0); // this
mv.getfield(builder.getClassName(), builder.getParameterConverterFieldName(i), ci(NativeDataConverter.class));
mv.aload(firstParam + i); // PyObject parameter
mv.invokevirtual(p(NativeDataConverter.class), "toNative", sig(PyObject.class, PyObject.class));
mv.astore(firstParam + i);
}
}
// Load and un-box parameters
for (int i = 0; i < signature.getParameterCount(); ++i) {
final NativeType parameterType = signature.getParameterType(i);
final int paramVar = i + firstParam;
mv.aload(paramVar);
switch (parameterType) {
case BOOL:
unbox(mv, "boolValue");
break;
case BYTE:
unbox(mv, "s8Value");
break;
case UBYTE:
unbox(mv, "u8Value");
break;
case SHORT:
unbox(mv, "s16Value");
break;
case USHORT:
unbox(mv, "u16Value");
break;
case INT:
unbox(mv, "s32Value");
break;
case UINT:
unbox(mv, "u32Value");
break;
case LONG:
if (Platform.getPlatform().longSize() == 32) {
unbox(mv, "s32Value");
} else {
unbox(mv, "s64Value");
}
break;
case ULONG:
if (Platform.getPlatform().longSize() == 32) {
unbox(mv, "u32Value");
} else {
unbox(mv, "u64Value");
}
break;
case LONGLONG:
unbox(mv, "s64Value");
break;
case ULONGLONG:
unbox(mv, "u64Value");
break;
case POINTER:
maxPointerIndex = i;
Label direct = new Label();
Label done = new Label();
Label converted = new Label();
// If a direct pointer is passed in, jump straight to conversion
mv.instance_of(p(Pointer.class));
mv.iftrue(direct);
mv.aload(paramVar);
mv.invokestatic(p(JITRuntime.class), "other2ptr", sig(PyObject.class, PyObject.class));
mv.label(converted);
mv.dup();
mv.astore(paramVar);
mv.instance_of(p(Pointer.class));
mv.iffalse(fallback[i]);
mv.label(direct);
// The parameter is guaranteed to be a direct pointer now
mv.aload(paramVar);
unbox(mv, "pointerValue");
mv.label(done);
break;
case FLOAT:
unbox(mv, "f32Value");
break;
case DOUBLE:
unbox(mv, "f64Value");
break;
default:
throw new UnsupportedOperationException("unsupported parameter type " + parameterType);
}
}
// stack now contains [ Invoker, Function, int/long args ]
mv.invokevirtual(p(com.kenai.jffi.Invoker.class),
getInvokerMethodName(signature),
getInvokerSignature(signature.getParameterCount()));
// box up the raw int/long result
boxResult(mv, signature.getResultType());
emitResultConversion(mv, builder, signature);;
mv.areturn();
// Generate code to pop all the converted arguments off the stack
// when falling back to buffer-invocation
if (maxPointerIndex >= 0) {
for (int i = maxPointerIndex; i > 0; i--) {
mv.label(fallback[i]);
if (int.class == nativeIntType) {
mv.pop();
} else {
mv.pop2();
}
}
mv.label(fallback[0]);
// Pop ThreadContext, Invoker and Function
mv.pop(); mv.pop();
// Call the fallback invoker
mv.aload(0);
mv.getfield(p(JITInvoker.class), "fallbackInvoker", ci(Invoker.class));
for (int i = 0; i < signature.getParameterCount(); i++) {
mv.aload(firstParam + i);
}
mv.invokevirtual(p(Invoker.class), "invoke",
sig(PyObject.class, params(PyObject.class, signature.getParameterCount())));
emitResultConversion(mv, builder, signature);
mv.areturn();
}
}
private void emitResultConversion(SkinnyMethodAdapter mv, AsmClassBuilder builder, JITSignature signature) {
if (signature.hasResultConverter()) {
mv.aload(0); // [ result, this ]
mv.getfield(builder.getClassName(), builder.getResultConverterFieldName(), ci(NativeDataConverter.class));
mv.swap(); // [ converter, result ]
mv.invokevirtual(p(NativeDataConverter.class), "fromNative", sig(PyObject.class, PyObject.class));
}
}
private void boxResult(SkinnyMethodAdapter mv, String boxMethodName) {
mv.invokestatic(p(JITRuntime.class), boxMethodName,
sig(PyObject.class, getInvokerIntType()));
}
private void boxResult(SkinnyMethodAdapter mv, NativeType type) {
switch (type) {
case BOOL:
boxResult(mv, "newBoolean");
break;
case BYTE:
boxResult(mv, "newSigned8");
break;
case UBYTE:
boxResult(mv, "newUnsigned8");
break;
case SHORT:
boxResult(mv, "newSigned16");
break;
case USHORT:
boxResult(mv, "newUnsigned16");
break;
case INT:
boxResult(mv, "newSigned32");
break;
case UINT:
boxResult(mv, "newUnsigned32");
break;
case LONG:
if (Platform.getPlatform().longSize() == 32) {
boxResult(mv, "newSigned32");
} else {
boxResult(mv, "newSigned64");
}
break;
case ULONG:
if (Platform.getPlatform().longSize() == 32) {
boxResult(mv, "newUnsigned32");
} else {
boxResult(mv, "newUnsigned64");
}
break;
case LONGLONG:
boxResult(mv, "newSigned64");
break;
case ULONGLONG:
boxResult(mv, "newUnsigned64");
break;
case FLOAT:
boxResult(mv, "newFloat32");
break;
case DOUBLE:
boxResult(mv, "newFloat64");
break;
case VOID:
boxResult(mv, "newNone");
break;
case POINTER:
boxResult(mv, "newPointer" + Platform.getPlatform().addressSize());
break;
case STRING:
boxResult(mv, "newString");
break;
default:
throw new UnsupportedOperationException("native return type not supported: " + type);
}
}
private void unbox(SkinnyMethodAdapter mv, String method) {
mv.invokestatic(p(JITRuntime.class), getRuntimeMethod(method), sig(getInvokerIntType(), PyObject.class));
}
private String getRuntimeMethod(String method) {
return method + (int.class == getInvokerIntType() ? "32" : "64");
}
abstract String getInvokerMethodName(JITSignature signature);
abstract String getInvokerSignature(int parameterCount);
abstract Class getInvokerIntType();
public static boolean isPrimitiveInt(Class c) {
return byte.class == c || char.class == c || short.class == c || int.class == c || boolean.class == c;
}
public static final void widen(SkinnyMethodAdapter mv, Class from, Class to) {
if (long.class == to && long.class != from && isPrimitiveInt(from)) {
mv.i2l();
}
}
public static final void narrow(SkinnyMethodAdapter mv, Class from, Class to) {
if (!from.equals(to) && isPrimitiveInt(to)) {
if (long.class == from) {
mv.l2i();
}
if (byte.class == to) {
mv.i2b();
} else if (short.class == to) {
mv.i2s();
} else if (char.class == to) {
mv.i2c();
} else if (boolean.class == to) {
// Ensure only 0x0 and 0x1 values are used for boolean
mv.iconst_1();
mv.iand();
}
}
}
protected static String[] buildSignatures(Class nativeIntClass, int maxParameters) {
char sigChar = int.class == nativeIntClass ? 'I' : 'J';
String[] signatures = new String[maxParameters + 1];
for (int i = 0; i < signatures.length; i++) {
StringBuilder sb = new StringBuilder();
sb.append('(').append(ci(com.kenai.jffi.Function.class));
for (int n = 0; n < i; n++) {
sb.append(sigChar);
}
signatures[i] = sb.append(")").append(sigChar).toString();
}
return signatures;
}
}