Skip to content

Commit

Permalink
Switch FFI jitted methods to invokeI<x>, invokeL<x>, invokeN<x> helpe…
Browse files Browse the repository at this point in the history
…r methods
  • Loading branch information
vp-of-awesome committed Apr 1, 2012
1 parent f29b9f6 commit 37113f6
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 456 deletions.
139 changes: 45 additions & 94 deletions src/org/jruby/ext/ffi/jffi/AbstractNumericMethodGenerator.java
@@ -1,8 +1,6 @@
package org.jruby.ext.ffi.jffi;

import com.kenai.jffi.ObjectParameterInfo;
import com.kenai.jffi.ObjectParameterStrategy;
import com.kenai.jffi.Platform;
import com.kenai.jffi.*;
import org.jruby.compiler.impl.SkinnyMethodAdapter;
import org.jruby.ext.ffi.NativeType;
import org.jruby.runtime.ThreadContext;
Expand Down Expand Up @@ -37,8 +35,11 @@ public void generate(AsmClassBuilder builder, SkinnyMethodAdapter mv, JITSignatu
mv.aload(1); // load ThreadContext arg for result boxing
mv.getstatic(p(JITNativeInvoker.class), "invoker", ci(com.kenai.jffi.Invoker.class));
mv.aload(0);
mv.getfield(p(JITNativeInvoker.class), "function", ci(com.kenai.jffi.Function.class));
// [ stack now contains: Invoker, Function ]
mv.getfield(p(JITNativeInvoker.class), "callContext", ci(CallContext.class));
mv.aload(0);
mv.getfield(p(JITNativeInvoker.class), "functionAddress", ci(long.class));

// [ stack now contains: Invoker, CalLContext, function address ]

final int firstParam = 2;
int nextLocalVar = firstParam + signature.getParameterCount();
Expand Down Expand Up @@ -139,7 +140,6 @@ public void generate(AsmClassBuilder builder, SkinnyMethodAdapter mv, JITSignatu
mv.invokevirtual(p(ObjectParameterStrategy.class), "isDirect", sig(boolean.class));
mv.iftrue(address);
mv.iinc(heapPointerCountVar, 1);

mv.label(address);
// It is now direct, get the address, and convert to the native int type
mv.aload(nextStrategyVar);
Expand Down Expand Up @@ -187,95 +187,48 @@ public void generate(AsmClassBuilder builder, SkinnyMethodAdapter mv, JITSignatu

// Handle non-direct pointer parameters
if (pointerCount > 0) {
final int MAX_PARAM_COUNT = 4;
final int MAX_POINTER_COUNT = 4;
mv.label(indirect);
boolean emitFallback = true;

// For functions with only a few pointer args, we can possibly use the jffi object fast-path
if (signature.getParameterCount() <= MAX_PARAM_COUNT && pointerCount <= MAX_POINTER_COUNT) {
Label fallback = new Label();
if ((emitFallback = pointerCount > 3)) {
mv.iload(heapPointerCountVar);
mv.iconst_3();
mv.if_icmpgt(fallback);
}

if (int.class == nativeIntType) {
// For i386, need to convert the int params to long to pass to the invokeNrN helpers
final int firstIntParam = nextLocalVar;
for (int i = 0; i < signature.getParameterCount() - 1; i++) {
mv.istore(firstIntParam + i);
}

// first param is still on operand stack, just convert in-place
mv.i2l();

// now convert the rest
for (int i = signature.getParameterCount() - 2; i >= 0; i--) {
mv.iload(firstIntParam + i);
mv.i2l();
}
if (int.class == nativeIntType) {
final int firstIntParam = nextLocalVar;
for (int i = 0; i < signature.getParameterCount() - 1; i++) {
mv.istore(firstIntParam + i);
}

mv.iload(heapPointerCountVar);

// Just load all the pointer parameters, conversion strategies and parameter info onto
// the operand stack, so the helper functions can sort them out.
for (int i = 0, ptrIdx = 0; i < signature.getParameterCount(); i++) {
switch (signature.getParameterType(i)) {
case POINTER:
case BUFFER_IN:
case BUFFER_OUT:
case BUFFER_INOUT:
case STRING:
case TRANSIENT_STRING:
mv.aload(firstParam + i);
mv.aload(firstStrategyVar + ptrIdx);
mv.aload(0);
mv.getfield(p(JITNativeInvoker.class), "parameterInfo" + i, ci(ObjectParameterInfo.class));
ptrIdx++;
break;
}
mv.i2l();
// reload the rest and convert to long
for (int i = signature.getParameterCount() - 2; i >= 0; i--) {
mv.iload(firstIntParam + i);
mv.i2l();
}


Class[] paramTypes = makeObjectParamSignature(signature, pointerCount);
mv.invokestatic(p(JITRuntime.class), "invokeN" + signature.getParameterCount() + "OrN",
sig(long.class, paramTypes));
narrow(mv, long.class, nativeIntType);
mv.go_to(boxResult);
if (emitFallback) mv.label(fallback);
}

// Emit the fallback code to call the generic invoker path.
if (emitFallback) {

// pop all the converted arguments off the stack
for (int i = 0; i < signature.getParameterCount(); i++) {
if (int.class == nativeIntType) {
mv.pop();
} else {
mv.pop2();
}
}

// Pop ThreadContext, Invoker and Function
mv.pop(); mv.pop(); mv.pop();

// Call the fallback invoker
mv.aload(0);
mv.getfield(builder.getClassName(), builder.getFallbackInvokerFieldName(), ci(NativeInvoker.class));
mv.aload(1);
mv.iload(heapPointerCountVar);

for (int i = 0; i < signature.getParameterCount(); i++) {
mv.aload(firstParam + i);
// Just load all the pointer parameters, conversion strategies and parameter info onto
// the operand stack, so the helper functions can sort them out.
for (int i = 0, ptrIdx = 0; i < signature.getParameterCount(); i++) {
switch (signature.getParameterType(i)) {
case POINTER:
case BUFFER_IN:
case BUFFER_OUT:
case BUFFER_INOUT:
case STRING:
case TRANSIENT_STRING:
mv.aload(firstParam + i);
mv.aload(firstStrategyVar + ptrIdx);
mv.aload(0);
mv.getfield(p(JITNativeInvoker.class), "parameterInfo" + i, ci(ObjectParameterInfo.class));
ptrIdx++;
break;
}

mv.invokevirtual(p(NativeInvoker.class), "invoke",
sig(IRubyObject.class, params(ThreadContext.class, IRubyObject.class, signature.getParameterCount())));
mv.go_to(resultConversion);
}


mv.invokevirtual(p(Invoker.class), "invokeN" + signature.getParameterCount(),
sig(long.class, makeObjectParamSignature(signature, pointerCount)));
narrow(mv, long.class, nativeIntType);
mv.go_to(boxResult);
}
}

Expand All @@ -294,8 +247,8 @@ private static Class[] makeObjectParamSignature(JITSignature signature, int poin
Class[] paramTypes = new Class[3 + signature.getParameterCount() + (pointerCount * 3)];
int idx = 0;

paramTypes[idx++] = com.kenai.jffi.Invoker.class;
paramTypes[idx++] = com.kenai.jffi.Function.class;
paramTypes[idx++] = CallContext.class;
paramTypes[idx++] = long.class;

for (int i = 0; i < signature.getParameterCount(); i++) {
paramTypes[idx++] = long.class;
Expand All @@ -304,17 +257,14 @@ private static Class[] makeObjectParamSignature(JITSignature signature, int poin
paramTypes[idx++] = int.class;

for (int i = 0; i < pointerCount; i++) {
paramTypes[idx++] = IRubyObject.class;
paramTypes[idx++] = PointerParameterStrategy.class;
paramTypes[idx++] = Object.class;
paramTypes[idx++] = ObjectParameterStrategy.class;
paramTypes[idx++] = ObjectParameterInfo.class;
}

return paramTypes;
}

private void emitHeapPointerLoad(SkinnyMethodAdapter mv, Signature signature, int lvar) {

}

private void unbox(SkinnyMethodAdapter mv, String method) {
mv.invokestatic(p(JITRuntime.class), getRuntimeMethod(method), sig(getInvokerIntType(), IRubyObject.class));
Expand Down Expand Up @@ -393,7 +343,8 @@ private void boxResult(SkinnyMethodAdapter mv, NativeType type) {
break;

case VOID:
boxResult(mv, "newNil");
if (int.class == getInvokerIntType()) mv.pop(); else mv.pop2();
mv.getfield(p(ThreadContext.class), "nil", ci(IRubyObject.class));
break;

case POINTER:
Expand Down Expand Up @@ -460,7 +411,7 @@ protected static String[] buildSignatures(Class nativeIntClass, int maxParameter

StringBuilder sb = new StringBuilder();

sb.append('(').append(ci(com.kenai.jffi.Function.class));
sb.append('(').append(ci(CallContext.class)).append(ci(long.class));

for (int n = 0; n < i; n++) {
sb.append(sigChar);
Expand Down
22 changes: 4 additions & 18 deletions src/org/jruby/ext/ffi/jffi/FastIntMethodGenerator.java
@@ -1,6 +1,7 @@
package org.jruby.ext.ffi.jffi;


import com.kenai.jffi.CallContext;
import com.kenai.jffi.CallingConvention;
import org.jruby.ext.ffi.NativeType;
import com.kenai.jffi.Platform;
Expand All @@ -14,21 +15,14 @@ final class FastIntMethodGenerator extends AbstractNumericMethodGenerator {
private static final String[] signatures = buildSignatures(int.class, MAX_PARAMETERS);

private static final String[] methodNames = {
"invokeVrI", "invokeIrI", "invokeIIrI", "invokeIIIrI", "invokeIIIIrI", "invokeIIIIIrI", "invokeIIIIIIrI"
"invokeI0", "invokeI1", "invokeI2", "invokeI3", "invokeI4", "invokeI5", "invokeI6"
};

private static final String[] noErrnoMethodNames = {
"invokeNoErrnoVrI", "invokeNoErrnoIrI", "invokeNoErrnoIIrI", "invokeNoErrnoIIIrI"
};

String getInvokerMethodName(JITSignature signature) {

final int parameterCount = signature.getParameterCount();

if (signature.isIgnoreError() && parameterCount <= MAX_PARAMETERS && parameterCount <= noErrnoMethodNames.length) {
return noErrnoMethodNames[signature.getParameterCount()];

} else if (parameterCount <= MAX_PARAMETERS && parameterCount <= methodNames.length) {
if (parameterCount <= MAX_PARAMETERS && parameterCount <= methodNames.length) {
return methodNames[parameterCount];

} else {
Expand Down Expand Up @@ -76,17 +70,9 @@ public boolean isSupported(JITSignature signature) {

final static int getMaximumFastIntParameters() {
try {
com.kenai.jffi.Invoker.class.getDeclaredMethod("invokeIIIIIIrI", com.kenai.jffi.Function.class,
com.kenai.jffi.Invoker.class.getDeclaredMethod("invokeI6", CallContext.class, long.class,
int.class, int.class, int.class, int.class, int.class, int.class);
return 6;
} catch (NoSuchMethodException nex) {
try {
com.kenai.jffi.Invoker.class.getDeclaredMethod("invokeIIIrI", com.kenai.jffi.Function.class,
int.class, int.class, int.class);
return 3;
} catch (NoSuchMethodException nex2) {
return -1;
}
} catch (Throwable t) {
return -1;
}
Expand Down
8 changes: 4 additions & 4 deletions src/org/jruby/ext/ffi/jffi/FastLongMethodGenerator.java
@@ -1,10 +1,10 @@
package org.jruby.ext.ffi.jffi;


import com.kenai.jffi.CallContext;
import com.kenai.jffi.CallingConvention;
import org.jruby.ext.ffi.NativeType;
import com.kenai.jffi.Platform;
import static org.jruby.util.CodegenUtils.*;
import org.jruby.ext.ffi.NativeType;

/**
*
Expand All @@ -15,7 +15,7 @@ final class FastLongMethodGenerator extends AbstractNumericMethodGenerator {
private static final String[] signatures = buildSignatures(long.class, MAX_PARAMETERS);

private static final String[] methodNames = {
"invokeVrL", "invokeLrL", "invokeLLrL", "invokeLLLrL", "invokeLLLLrL", "invokeLLLLLrL", "invokeLLLLLLrL"
"invokeL0", "invokeL1", "invokeL2", "invokeL3", "invokeL4", "invokeL5", "invokeL6"
};

String getInvokerMethodName(JITSignature signature) {
Expand Down Expand Up @@ -71,7 +71,7 @@ public boolean isSupported(JITSignature signature) {

final static int getMaximumFastLongParameters() {
try {
com.kenai.jffi.Invoker.class.getDeclaredMethod("invokeLLLLLLrL", com.kenai.jffi.Function.class,
com.kenai.jffi.Invoker.class.getDeclaredMethod("invokeL6", CallContext.class, long.class,
long.class, long.class, long.class, long.class, long.class, long.class);
return 6;
} catch (Throwable t) {
Expand Down
8 changes: 4 additions & 4 deletions src/org/jruby/ext/ffi/jffi/FastNumericMethodGenerator.java
@@ -1,10 +1,10 @@
package org.jruby.ext.ffi.jffi;


import com.kenai.jffi.CallContext;
import com.kenai.jffi.CallingConvention;
import org.jruby.ext.ffi.NativeType;
import com.kenai.jffi.Platform;
import static org.jruby.util.CodegenUtils.*;
import org.jruby.ext.ffi.NativeType;

/**
*
Expand All @@ -15,7 +15,7 @@ final class FastNumericMethodGenerator extends AbstractNumericMethodGenerator {
private static final String[] signatures = buildSignatures(long.class, MAX_PARAMETERS);

private static final String[] methodNames = {
"invokeVrN", "invokeNrN", "invokeNNrN", "invokeNNNrN", "invokeNNNNrN", "invokeNNNNNrN", "invokeNNNNNNrN"
"invokeN0", "invokeN1", "invokeN2", "invokeN3", "invokeN4", "invokeN5", "invokeN6"
};

String getInvokerMethodName(JITSignature signature) {
Expand Down Expand Up @@ -71,7 +71,7 @@ public boolean isSupported(JITSignature signature) {

final static int getMaximumFastNumericParameters() {
try {
com.kenai.jffi.Invoker.class.getDeclaredMethod("invokeNNNNNNrN", com.kenai.jffi.Function.class,
com.kenai.jffi.Invoker.class.getDeclaredMethod("invokeN6", CallContext.class, long.class,
long.class, long.class, long.class, long.class, long.class, long.class);
return 6;
} catch (Throwable t) {
Expand Down
4 changes: 4 additions & 0 deletions src/org/jruby/ext/ffi/jffi/JITNativeInvoker.java
Expand Up @@ -14,6 +14,8 @@ abstract public class JITNativeInvoker extends NativeInvoker {
protected static final Invoker invoker = Invoker.getInstance();
protected final NativeInvoker fallbackInvoker;
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;
Expand All @@ -33,6 +35,8 @@ abstract public class JITNativeInvoker extends NativeInvoker {
public JITNativeInvoker(com.kenai.jffi.Function function, Signature signature, NativeInvoker fallbackInvoker) {
this.arity = signature.getParameterCount();
this.function = function;
this.callContext = function.getCallContext();
this.functionAddress = function.getFunctionAddress();
this.signature = signature;
this.fallbackInvoker = fallbackInvoker;

Expand Down

0 comments on commit 37113f6

Please sign in to comment.