package org.jruby.ext.ffi.jffi;
import org.jruby.*;
import org.jruby.ext.ffi.*;
import org.jruby.internal.runtime.methods.DynamicMethod;
import org.jruby.runtime.Block;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.callsite.CachingCallSite;
import java.math.BigInteger;
public final class JITRuntime {
private JITRuntime() {}
public static RuntimeException newArityError(ThreadContext context, int got, int expected) {
return context.runtime.newArgumentError(got, expected);
}
public static long other2long(IRubyObject parameter) {
return RubyNumeric.num2long(parameter);
}
public static int s8Value32(IRubyObject parameter) {
return (byte) (parameter instanceof RubyFixnum
? ((RubyFixnum) parameter).getLongValue()
: other2long(parameter));
}
public static long s8Value64(IRubyObject parameter) {
return (byte) (parameter instanceof RubyFixnum
? ((RubyFixnum) parameter).getLongValue()
: other2long(parameter));
}
public static int u8Value32(IRubyObject parameter) {
return (int) ((parameter instanceof RubyFixnum
? ((RubyFixnum) parameter).getLongValue()
: other2long(parameter)) & 0xffL);
}
public static long u8Value64(IRubyObject parameter) {
return (parameter instanceof RubyFixnum
? ((RubyFixnum) parameter).getLongValue()
: other2long(parameter)) & 0xffL;
}
public static int s16Value32(IRubyObject parameter) {
return (short) (parameter instanceof RubyFixnum
? ((RubyFixnum) parameter).getLongValue()
: other2long(parameter));
}
public static long s16Value64(IRubyObject parameter) {
return (short) (parameter instanceof RubyFixnum
? ((RubyFixnum) parameter).getLongValue()
: other2long(parameter));
}
public static int u16Value32(IRubyObject parameter) {
return (int) (((parameter instanceof RubyFixnum)
? ((RubyFixnum) parameter).getLongValue()
: other2long(parameter)) & 0xffffL);
}
public static long u16Value64(IRubyObject parameter) {
return ((parameter instanceof RubyFixnum)
? ((RubyFixnum) parameter).getLongValue()
: other2long(parameter)) & 0xffffL;
}
public static int s32Value32(IRubyObject parameter) {
return (int) (parameter instanceof RubyFixnum
? ((RubyFixnum) parameter).getLongValue()
: other2long(parameter));
}
public static long s32Value64(IRubyObject parameter) {
return (int) (parameter instanceof RubyFixnum
? ((RubyFixnum) parameter).getLongValue()
: other2long(parameter));
}
public static int u32Value32(IRubyObject parameter) {
return (int) ((parameter instanceof RubyFixnum
? ((RubyFixnum) parameter).getLongValue()
: other2long(parameter)) & 0xffffffffL);
}
public static long u32Value64(IRubyObject parameter) {
return (parameter instanceof RubyFixnum
? ((RubyFixnum) parameter).getLongValue()
: other2long(parameter)) & 0xffffffffL;
}
public static long s64Value64(IRubyObject parameter) {
return parameter instanceof RubyFixnum
? ((RubyFixnum) parameter).getLongValue()
: other2long(parameter);
}
public static long other2u64(IRubyObject parameter) {
if (parameter instanceof RubyBignum) {
return ((RubyBignum) parameter).getValue().longValue();
} else {
return other2long(parameter);
}
}
public static long u64Value64(IRubyObject parameter) {
return parameter instanceof RubyFixnum
? ((RubyFixnum) parameter).getLongValue()
: other2u64(parameter);
}
public static int f32Value32(IRubyObject parameter) {
if (parameter instanceof RubyFloat) {
return Float.floatToRawIntBits((float) ((RubyFloat) parameter).getDoubleValue());
} else {
return (int) other2long(parameter);
}
}
public static long f32Value64(IRubyObject parameter) {
if (parameter instanceof RubyFloat) {
return Float.floatToRawIntBits((float) ((RubyFloat) parameter).getDoubleValue());
} else {
return other2long(parameter);
}
}
public static long f64Value64(IRubyObject parameter) {
if (parameter instanceof RubyFloat) {
return Double.doubleToRawLongBits(((RubyFloat) parameter).getDoubleValue());
} else {
return other2long(parameter);
}
}
public static int boolValue32(IRubyObject parameter) {
return boolValue(parameter) ? 1 : 0;
}
public static long boolValue64(IRubyObject parameter) {
return boolValue(parameter) ? 1L : 0L;
}
private static boolean other2bool(IRubyObject parameter) {
if (parameter instanceof RubyNumeric) {
return ((RubyNumeric) parameter).getLongValue() != 0;
}
throw parameter.getRuntime().newTypeError("cannot convert "
+ parameter.getMetaClass().getRealClass() + " to bool");
}
public static boolean boolValue(IRubyObject parameter) {
if (parameter instanceof RubyBoolean) {
return parameter.isTrue();
}
return other2bool(parameter);
}
public static IRubyObject other2ptr(ThreadContext context, IRubyObject parameter) {
if (parameter instanceof Struct) {
return ((Struct) parameter).getMemory();
} else if (parameter instanceof RubyString || parameter instanceof Buffer || parameter.isNil()) {
return parameter;
}
return convert2ptr(context, parameter);
}
public static IRubyObject convert2ptr(ThreadContext context, IRubyObject parameter) {
final int MAXRECURSE = 4;
IRubyObject ptr = parameter;
for (int i = 0; i < MAXRECURSE && !(ptr instanceof AbstractMemory) && ptr.respondsTo("to_ptr"); i++) {
ptr = ptr.callMethod(context, "to_ptr");
}
return ptr;
}
public static IRubyObject newSigned8(ThreadContext context, int value) {
return RubyFixnum.newFixnum(context.runtime, (byte) value);
}
public static IRubyObject newSigned8(Ruby runtime, int value) {
return RubyFixnum.newFixnum(runtime, (byte) value);
}
public static IRubyObject newSigned8(ThreadContext context, long value) {
return RubyFixnum.newFixnum(context.runtime, (byte) value);
}
public static IRubyObject newSigned8(Ruby runtime, long value) {
return RubyFixnum.newFixnum(runtime, (byte) value);
}
public static IRubyObject newUnsigned8(ThreadContext context, int value) {
int n = (byte) value;
return RubyFixnum.newFixnum(context.runtime, n < 0 ? ((n & 0x7F) + 0x80) : n);
}
public static IRubyObject newUnsigned8(Ruby runtime, int value) {
int n = (byte) value;
return RubyFixnum.newFixnum(runtime, n < 0 ? ((n & 0x7F) + 0x80) : n);
}
public static IRubyObject newUnsigned8(ThreadContext context, long value) {
int n = (byte) value;
return RubyFixnum.newFixnum(context.runtime, n < 0 ? ((n & 0x7F) + 0x80) : n);
}
public static IRubyObject newUnsigned8(Ruby runtime, long value) {
int n = (byte) value;
return RubyFixnum.newFixnum(runtime, n < 0 ? ((n & 0x7F) + 0x80) : n);
}
public static IRubyObject newSigned16(ThreadContext context, int value) {
return RubyFixnum.newFixnum(context.runtime, (short) value);
}
public static IRubyObject newSigned16(Ruby runtime, int value) {
return RubyFixnum.newFixnum(runtime, (short) value);
}
public static IRubyObject newSigned16(ThreadContext context, long value) {
return RubyFixnum.newFixnum(context.runtime, (short) value);
}
public static IRubyObject newSigned16(Ruby runtime, long value) {
return RubyFixnum.newFixnum(runtime, (short) value);
}
public static IRubyObject newUnsigned16(ThreadContext context, int value) {
int n = (short) value;
return RubyFixnum.newFixnum(context.runtime, n < 0 ? ((n & 0x7FFF) + 0x8000) : n);
}
public static IRubyObject newUnsigned16(Ruby runtime, int value) {
int n = (short) value;
return RubyFixnum.newFixnum(runtime, n < 0 ? ((n & 0x7FFF) + 0x8000) : n);
}
public static IRubyObject newUnsigned16(ThreadContext context, long value) {
int n = (short) value;
return RubyFixnum.newFixnum(context.runtime, n < 0 ? ((n & 0x7FFF) + 0x8000) : n);
}
public static IRubyObject newUnsigned16(Ruby runtime, long value) {
int n = (short) value;
return RubyFixnum.newFixnum(runtime, n < 0 ? ((n & 0x7FFF) + 0x8000) : n);
}
public static IRubyObject newSigned32(ThreadContext context, int value) {
return RubyFixnum.newFixnum(context.runtime, value);
}
public static IRubyObject newSigned32(Ruby runtime, int value) {
return RubyFixnum.newFixnum(runtime, value);
}
public static IRubyObject newSigned32(ThreadContext context, long value) {
return RubyFixnum.newFixnum(context.runtime, (int) value);
}
public static IRubyObject newSigned32(Ruby runtime, long value) {
return RubyFixnum.newFixnum(runtime, (int) value);
}
public static IRubyObject newUnsigned32(ThreadContext context, int value) {
long n = value;
return RubyFixnum.newFixnum(context.runtime, n < 0 ? ((n & 0x7FFFFFFFL) + 0x80000000L) : n);
}
public static IRubyObject newUnsigned32(Ruby runtime, int value) {
long n = value;
return RubyFixnum.newFixnum(runtime, n < 0 ? ((n & 0x7FFFFFFFL) + 0x80000000L) : n);
}
public static IRubyObject newUnsigned32(ThreadContext context, long value) {
long n = (int) value;
return RubyFixnum.newFixnum(context.runtime, n < 0 ? ((n & 0x7FFFFFFFL) + 0x80000000L) : n);
}
public static IRubyObject newUnsigned32(Ruby runtime, long value) {
long n = (int) value;
return RubyFixnum.newFixnum(runtime, n < 0 ? ((n & 0x7FFFFFFFL) + 0x80000000L) : n);
}
public static IRubyObject newSigned64(ThreadContext context, long value) {
return RubyFixnum.newFixnum(context.runtime, value);
}
public static IRubyObject newSigned64(Ruby runtime, long value) {
return RubyFixnum.newFixnum(runtime, value);
}
private static final BigInteger UINT64_BASE = BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE);
public static IRubyObject newUnsigned64(ThreadContext context, long value) {
return value < 0
? RubyBignum.newBignum(context.runtime, BigInteger.valueOf(value & 0x7fffffffffffffffL).add(UINT64_BASE))
: RubyFixnum.newFixnum(context.runtime, value);
}
public static IRubyObject newUnsigned64(Ruby runtime, long value) {
return value < 0
? RubyBignum.newBignum(runtime, BigInteger.valueOf(value & 0x7fffffffffffffffL).add(UINT64_BASE))
: RubyFixnum.newFixnum(runtime, value);
}
public static IRubyObject newNil(ThreadContext context, int ignored) {
return context.nil;
}
public static IRubyObject newNil(Ruby runtime, int ignored) {
return runtime.getNil();
}
public static IRubyObject newNil(ThreadContext context, long ignored) {
return context.nil;
}
public static IRubyObject newNil(Ruby runtime, long ignored) {
return runtime.getNil();
}
public static IRubyObject newPointer32(ThreadContext context, int address) {
Ruby runtime = context.runtime;
return new Pointer(runtime,
NativeMemoryIO.wrap(runtime, ((long) address) & 0xffffffffL));
}
public static IRubyObject newPointer32(Ruby runtime, int address) {
return new Pointer(runtime,
NativeMemoryIO.wrap(runtime, ((long) address) & 0xffffffffL));
}
public static IRubyObject newPointer32(ThreadContext context, long address) {
Ruby runtime = context.runtime;
return new Pointer(runtime,
NativeMemoryIO.wrap(runtime, address & 0xffffffffL));
}
public static IRubyObject newPointer32(Ruby runtime, long address) {
return new Pointer(runtime,
NativeMemoryIO.wrap(runtime, address & 0xffffffffL));
}
public static IRubyObject newPointer64(ThreadContext context, long address) {
Ruby runtime = context.runtime;
return new Pointer(runtime, NativeMemoryIO.wrap(runtime, address));
}
public static IRubyObject newPointer64(Ruby runtime, long address) {
return new Pointer(runtime, NativeMemoryIO.wrap(runtime, address));
}
public static IRubyObject newString(ThreadContext context, int address) {
return FFIUtil.getString(context.runtime, address);
}
public static IRubyObject newString(Ruby runtime, int address) {
return FFIUtil.getString(runtime, address);
}
public static IRubyObject newString(ThreadContext context, long address) {
return FFIUtil.getString(context.runtime, address);
}
public static IRubyObject newString(Ruby runtime, long address) {
return FFIUtil.getString(runtime, address);
}
public static IRubyObject newBoolean(ThreadContext context, int value) {
return context.runtime.newBoolean((value & 0x1) != 0);
}
public static IRubyObject newBoolean(Ruby runtime, int value) {
return runtime.newBoolean((value & 0x1) != 0);
}
public static IRubyObject newBoolean(ThreadContext context, long value) {
return context.runtime.newBoolean((value & 0x1L) != 0);
}
public static IRubyObject newBoolean(Ruby runtime, long value) {
return runtime.newBoolean((value & 0x1L) != 0);
}
public static IRubyObject newFloat32(ThreadContext context, int value) {
return RubyFloat.newFloat(context.runtime, Float.intBitsToFloat(value));
}
public static IRubyObject newFloat32(Ruby runtime, int value) {
return RubyFloat.newFloat(runtime, Float.intBitsToFloat(value));
}
public static IRubyObject newFloat32(ThreadContext context, long value) {
return RubyFloat.newFloat(context.runtime, Float.intBitsToFloat((int) value));
}
public static IRubyObject newFloat32(Ruby runtime, long value) {
return RubyFloat.newFloat(runtime, Float.intBitsToFloat((int) value));
}
public static IRubyObject newFloat64(ThreadContext context, long value) {
return RubyFloat.newFloat(context.runtime, Double.longBitsToDouble(value));
}
public static IRubyObject newFloat64(Ruby runtime, long value) {
return RubyFloat.newFloat(runtime, Double.longBitsToDouble(value));
}
private static final PointerParameterStrategy DIRECT_MEMORY_OBJECT = new MemoryObjectParameterStrategy(true);
private static final PointerParameterStrategy HEAP_MEMORY_OBJECT = new MemoryObjectParameterStrategy(false);
private static final PointerParameterStrategy DIRECT_MEMORY_IO = new MemoryIOParameterStrategy(true);
private static final PointerParameterStrategy HEAP_MEMORY_IO = new MemoryIOParameterStrategy(false);
private static final PointerParameterStrategy NIL_POINTER_STRATEGY = new NilPointerParameterStrategy();
private static final PointerParameterStrategy HEAP_STRING_POINTER_STRATEGY = new StringParameterStrategy(false, false);
private static final PointerParameterStrategy TRANSIENT_STRING_PARAMETER_STRATEGY = new StringParameterStrategy(false, true);
private static final PointerParameterStrategy DIRECT_STRING_PARAMETER_STRATEGY = new StringParameterStrategy(true, true);
public static PointerParameterStrategy lookupPointerParameterStrategy(IRubyObject parameter) {
if (parameter instanceof MemoryObject) {
return ((MemoryObject) parameter).getMemoryIO().isDirect() ? DIRECT_MEMORY_OBJECT : HEAP_MEMORY_OBJECT;
} else if (parameter instanceof RubyNil) {
return NIL_POINTER_STRATEGY;
} else if (parameter instanceof RubyString) {
return HEAP_STRING_POINTER_STRATEGY;
}
return null;
}
public static MemoryIO lookupPointerMemoryIO(IRubyObject parameter) {
if (parameter instanceof MemoryObject) {
return ((MemoryObject) parameter).getMemoryIO();
} else if (parameter instanceof RubyNil) {
return NilPointerParameterStrategy.NullMemoryIO.INSTANCE;
} else if (parameter instanceof RubyString) {
return StringParameterStrategy.getMemoryIO((RubyString) parameter, false, false);
}
return null;
}
public static MemoryIO getPointerMemoryIO(IRubyObject parameter) {
MemoryIO memory = lookupPointerMemoryIO(parameter);
if (memory != null) {
return memory;
} else {
return convertToPointerMemoryIO(parameter);
}
}
private static MemoryIO convertToPointerMemoryIO(IRubyObject parameter) {
IRubyObject obj = parameter;
ThreadContext context = parameter.getRuntime().getCurrentContext();
for (int depth = 0; depth < 4; depth++) {
if (obj.respondsTo("to_ptr")) {
obj = obj.callMethod(context, "to_ptr");
MemoryIO memory = lookupPointerMemoryIO(obj);
if (memory != null) {
return memory;
}
} else {
throw parameter.getRuntime().newTypeError("cannot convert parameter to native pointer");
}
}
throw parameter.getRuntime().newRuntimeError("to_ptr recursion limit reached for " + parameter.getMetaClass());
}
private static MemoryIO convertToStringMemoryIO(IRubyObject parameter, ThreadContext context, CachingCallSite callSite,
boolean isDirect, boolean checkStringSafety) {
DynamicMethod conversionMethod;
if (parameter instanceof RubyString) {
return StringParameterStrategy.getMemoryIO((RubyString) parameter, isDirect, checkStringSafety);
} else if (parameter instanceof RubyNil) {
return NilPointerParameterStrategy.NullMemoryIO.INSTANCE;
} else if (!(conversionMethod = callSite.retrieveCache(parameter).method).isUndefined()) {
IRubyObject convertedParameter = conversionMethod.call(context, parameter, parameter.getMetaClass(), callSite.getMethodName(), Block.NULL_BLOCK);
if (convertedParameter instanceof RubyString) {
return StringParameterStrategy.getMemoryIO((RubyString) convertedParameter, isDirect, checkStringSafety);
}
}
return StringParameterStrategy.getMemoryIO(parameter.convertToString(), isDirect, checkStringSafety);
}
public static MemoryIO convertToStringMemoryIO(IRubyObject parameter, ThreadContext context, CachingCallSite callSite) {
return convertToStringMemoryIO(parameter, context, callSite, true, true);
}
public static MemoryIO convertToTransientStringMemoryIO(IRubyObject parameter, ThreadContext context, CachingCallSite callSite) {
return convertToStringMemoryIO(parameter, context, callSite, false, true);
}
public static PointerParameterStrategy getMemoryIOStrategy(MemoryIO memory) {
return memory.isDirect() ? DIRECT_MEMORY_IO : HEAP_MEMORY_IO;
}
public static PointerParameterStrategy pointerParameterStrategy(IRubyObject parameter) {
PointerParameterStrategy strategy = lookupPointerParameterStrategy(parameter);
if (strategy != null) {
return strategy;
} else if (parameter.respondsTo("to_ptr")) {
IRubyObject ptr = parameter.callMethod(parameter.getRuntime().getCurrentContext(), "to_ptr");
return new DelegatingPointerParameterStrategy(ptr, pointerParameterStrategy(ptr));
} else {
throw parameter.getRuntime().newTypeError("cannot convert parameter to native pointer");
}
}
public static PointerParameterStrategy stringParameterStrategy(IRubyObject parameter) {
if (parameter instanceof RubyString) {
return DIRECT_STRING_PARAMETER_STRATEGY;
} else if (parameter.isNil()) {
return NIL_POINTER_STRATEGY;
} else {
return stringParameterStrategy(parameter.convertToString());
}
}
public static PointerParameterStrategy transientStringParameterStrategy(IRubyObject parameter) {
if (parameter instanceof RubyString) {
return TRANSIENT_STRING_PARAMETER_STRATEGY;
} else if (parameter.isNil()) {
return NIL_POINTER_STRATEGY;
} else {
return transientStringParameterStrategy(parameter.convertToString());
}
}
public static MemoryIO convertToPointerMemoryIO(ThreadContext context, IRubyObject parameter, CachingCallSite callSite) {
DynamicMethod method = getConversionMethod(parameter, callSite);
IRubyObject ptr = method.call(context, parameter, parameter.getMetaClass(), callSite.getMethodName(), Block.NULL_BLOCK);
if (ptr instanceof AbstractMemory) {
return ((AbstractMemory) ptr).getMemoryIO();
}
throw parameter.getRuntime().newTypeError(parameter.getMetaClass() + "#" + callSite.getMethodName()
+ " should return " + context.runtime.getFFI().pointerClass);
}
public static DynamicMethod getConversionMethod(IRubyObject parameter, CachingCallSite callSite) {
DynamicMethod method = callSite.retrieveCache(parameter).method;
if (method.isUndefined()) {
throw parameter.getRuntime().newTypeError("cannot convert parameter of type " + parameter.getMetaClass()
+ " to native pointer; does not respond to :" + callSite.getMethodName());
}
return method;
}
public static boolean isDirectPointer(IRubyObject parameter) {
return parameter instanceof MemoryObject && ((MemoryObject) parameter).getMemoryIO().isDirect();
}
public static int pointerValue32(IRubyObject parameter) {
return (int) ((MemoryObject) parameter).getMemoryIO().address();
}
public static long pointerValue64(IRubyObject parameter) {
return ((MemoryObject) parameter).getMemoryIO().address();
}
public static boolean isTrue(boolean p1) {
return p1;
}
public static boolean isTrue(boolean p1, boolean p2) {
return p1 & p2;
}
public static boolean isTrue(boolean p1, boolean p2, boolean p3) {
return p1 & p2 & p3;
}
public static boolean isTrue(boolean p1, boolean p2, boolean p3, boolean p4) {
return p1 & p2 & p3 & p4;
}
public static boolean isTrue(boolean p1, boolean p2, boolean p3, boolean p4, boolean p5) {
return p1 & p2 & p3 & p4 & p5;
}
public static boolean isTrue(boolean p1, boolean p2, boolean p3, boolean p4, boolean p5, boolean p6) {
return p1 & p2 & p3 & p4 & p5 & p5 & p6;
}
}