jnr.ffi.provider.jffi.BaseMethodGenerator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jnr-ffi Show documentation
Show all versions of jnr-ffi Show documentation
A library for invoking native functions from java
package jnr.ffi.provider.jffi;
import com.kenai.jffi.CallContext;
import com.kenai.jffi.Function;
import jnr.ffi.mapper.*;
import static jnr.ffi.provider.jffi.AsmUtil.*;
import static jnr.ffi.provider.jffi.CodegenUtils.*;
import static jnr.ffi.provider.jffi.NumberUtil.getBoxedClass;
import static org.objectweb.asm.Opcodes.ACC_FINAL;
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
/**
*
*/
abstract class BaseMethodGenerator implements MethodGenerator {
public void generate(AsmBuilder builder, String functionName, Function function, Signature signature) {
ResultType resultType = InvokerUtil.getResultType(NativeRuntime.getInstance(),
signature.resultType, signature.resultAnnotations, null);
ParameterType[] parameterTypes = new ParameterType[signature.parameterTypes.length];
for (int i = 0; i < parameterTypes.length; i++) {
parameterTypes[i] = InvokerUtil.getParameterType(NativeRuntime.getInstance(),
signature.parameterTypes[i], signature.parameterAnnotations[i], null);
}
generate(builder, functionName, function, resultType, parameterTypes, signature.ignoreError);
}
public void generate(AsmBuilder builder, String functionName, Function function,
ResultType resultType, ParameterType[] parameterTypes, boolean ignoreError) {
Class[] javaParameterTypes = new Class[parameterTypes.length];
for (int i = 0; i < parameterTypes.length; i++) {
javaParameterTypes[i] = parameterTypes[i].getDeclaredType();
}
SkinnyMethodAdapter mv = new SkinnyMethodAdapter(builder.getClassVisitor().visitMethod(ACC_PUBLIC | ACC_FINAL,
functionName,
sig(resultType.getDeclaredType(), javaParameterTypes), null, null));
mv.start();
// Retrieve the static 'ffi' Invoker instance
mv.getstatic(p(AbstractAsmLibraryInterface.class), "ffi", ci(com.kenai.jffi.Invoker.class));
// retrieve the call context and function address
mv.aload(0);
mv.getfield(builder.getClassNamePath(), builder.getCallContextFieldName(function), ci(CallContext.class));
mv.aload(0);
mv.getfield(builder.getClassNamePath(), builder.getFunctionAddressFieldName(function), ci(long.class));
LocalVariableAllocator localVariableAllocator = new LocalVariableAllocator(parameterTypes);
generate(builder, mv, localVariableAllocator, function, resultType, parameterTypes, ignoreError);
mv.visitMaxs(100, localVariableAllocator.getSpaceUsed());
mv.visitEnd();
}
abstract void generate(AsmBuilder builder, SkinnyMethodAdapter mv, LocalVariableAllocator localVariableAllocator, Function function, ResultType resultType, ParameterType[] parameterTypes,
boolean ignoreError);
static void loadAndConvertParameter(AsmBuilder builder, SkinnyMethodAdapter mv, LocalVariable parameter,
ParameterType parameterType) {
ToNativeConverter parameterConverter = parameterType.toNativeConverter;
if (parameterConverter != null) {
mv.aload(0);
mv.getfield(builder.getClassNamePath(), builder.getToNativeConverterName(parameterConverter), ci(ToNativeConverter.class));
}
AsmUtil.load(mv, parameterType.getDeclaredType(), parameter);
if (parameterConverter != null) {
if (parameterType.getDeclaredType().isPrimitive()) {
boxValue(mv, getBoxedClass(parameterType.getDeclaredType()), parameterType.getDeclaredType());
}
mv.aconst_null();
mv.invokeinterface(ToNativeConverter.class, "toNative",
Object.class, Object.class, ToNativeContext.class);
mv.checkcast(p(parameterConverter.nativeType()));
}
}
static void convertAndReturnResult(AsmBuilder builder, SkinnyMethodAdapter mv, ResultType resultType, Class nativeResultClass) {
// If there is a result converter, retrieve it and put on the stack
FromNativeConverter resultConverter = resultType.fromNativeConverter;
if (resultConverter != null) {
boxValue(mv, resultConverter.nativeType(), nativeResultClass);
mv.aload(0);
mv.getfield(builder.getClassNamePath(), builder.getFromNativeConverterName(resultConverter), ci(FromNativeConverter.class));
mv.swap();
mv.aconst_null();
mv.invokeinterface(FromNativeConverter.class, "fromNative",
Object.class, Object.class, FromNativeContext.class);
if (resultType.getDeclaredType().isPrimitive()) {
// The actual return type is a primitive, but there was a converter for it - extract the primitive value
Class boxedType = getBoxedClass(resultType.getDeclaredType());
mv.checkcast(p(boxedType));
unboxNumber(mv, boxedType, resultType.getDeclaredType(), resultType.nativeType);
emitReturnOp(mv, resultType.getDeclaredType());
} else {
mv.checkcast(p(resultType.getDeclaredType()));
mv.areturn();
}
} else {
AsmUtil.emitReturn(mv, resultType.getDeclaredType(), nativeResultClass);
}
}
static void emitPostInvoke(AsmBuilder builder, SkinnyMethodAdapter mv, ParameterType[] parameterTypes,
LocalVariable[] parameters, LocalVariable[] converted) {
for (int i = 0; i < converted.length; ++i) {
if (converted[i] != null) {
mv.aload(0);
mv.getfield(builder.getClassNamePath(), builder.getToNativeConverterName(parameterTypes[i].toNativeConverter),
ci(ToNativeConverter.class));
mv.checkcast(ToNativeConverter.PostInvocation.class);
mv.aload(parameters[i]);
mv.aload(converted[i]);
mv.aconst_null();
mv.invokeinterface(ToNativeConverter.PostInvocation.class, "postInvoke", void.class,
Object.class, Object.class, ToNativeContext.class);
}
}
}
}