jffi-1.0.2/0000755000175000017500000000000011424636215012372 5ustar twernertwernerjffi-1.0.2/.project0000644000175000017500000000105611424636215014043 0ustar twernertwerner jffi org.eclipse.jdt.core.javabuilder org.maven.ide.eclipse.maven2Builder org.maven.ide.eclipse.maven2Nature org.eclipse.jdt.core.javanature jffi-1.0.2/test/0000755000175000017500000000000011424636215013351 5ustar twernertwernerjffi-1.0.2/test/com/0000755000175000017500000000000011424636215014127 5ustar twernertwernerjffi-1.0.2/test/com/kenai/0000755000175000017500000000000011424636215015216 5ustar twernertwernerjffi-1.0.2/test/com/kenai/jffi/0000755000175000017500000000000011424636215016134 5ustar twernertwernerjffi-1.0.2/test/com/kenai/jffi/UnitHelper.java0000644000175000017500000005453611424636215021073 0ustar twernertwerner package com.kenai.jffi; import java.io.File; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; public class UnitHelper { public enum InvokerType { Default, FastInt, FastLong, FastNumeric, PointerArray } public static final class Address extends java.lang.Number { public final int SIZE = Platform.getPlatform().addressSize(); public final long address; public Address(long address) { this.address = address; } public Address(Closure.Handle closure) { this(closure.getAddress()); } @Override public int intValue() { return (int) address; } @Override public long longValue() { return address; } @Override public float floatValue() { return (float) address; } @Override public double doubleValue() { return (double) address; } } public static final String getCLibraryName() { switch (Platform.getPlatform().getOS()) { case LINUX: return "libc.so.6"; case DARWIN: return "libc.dylib"; case WINDOWS: return "msvcrt.dll"; case AIX: if (Platform.getPlatform().addressSize() == 32){ return "libc.a(shr.o)"; } else { return "libc.a(shr_64.o)"; } default: return "libc.so"; } } public static T loadTestLibrary(Class interfaceClass) { return loadTestLibrary(interfaceClass, InvokerType.Default); } public static T loadTestLibrary(Class interfaceClass, InvokerType invokerType) { String name = Platform.getPlatform().mapLibraryName("test"); return loadLibrary(new File("build", name).getAbsolutePath(), interfaceClass, invokerType); } /** * Creates a new InvocationHandler mapping methods in the interfaceClass * to functions in the native library. * @param the type of interfaceClass * @param libraryName the native library to load * @param interfaceClass the interface that contains the native method description * @return a new instance of interfaceClass that can be used to call * functions in the native library. */ public static T loadLibrary(String name, Class interfaceClass, InvokerType invokerType) { Library lib = Library.getCachedInstance(name, Library.LAZY); if (lib == null) { throw new UnsatisfiedLinkError(String.format("Could not load '%s': %s", name, Library.getLastError())); } return interfaceClass.cast(Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class[]{ interfaceClass }, new NativeInvocationHandler(lib, invokerType))); } private static final class LibraryHolder { static final Library libtest = Library.getCachedInstance( new File("build", Platform.getPlatform().mapLibraryName("test")).getAbsolutePath(), Library.LAZY); } public static Address findSymbol(String name) { final long address = LibraryHolder.libtest.getSymbolAddress(name); if (address == 0L) { throw new UnsatisfiedLinkError("Could not locate symbol '" + name + "'"); } return new Address(address); } private static final class NativeInvocationHandler implements InvocationHandler { private final ConcurrentMap invokers = new ConcurrentHashMap(); private final Library library; private final InvokerType invokerType; public NativeInvocationHandler(Library library, InvokerType invokerType) { this.library = library; this.invokerType = invokerType; } public Object invoke(Object self, Method method, Object[] argArray) throws Throwable { return getMethodInvoker(method).invoke(argArray); } /** * Gets the {@link Invoker} for a method. * * @param method the method defined in the interface class * @return the Invoker to use to invoke the native function */ private final MethodInvoker getMethodInvoker(Method method) { MethodInvoker invoker = invokers.get(method); if (invoker != null) { return invoker; } invokers.put(method, invoker = createInvoker(library, method, invokerType)); return invoker; } } private static final MethodInvoker createInvoker(Library library, Method method, InvokerType invokerType) { Class returnType = method.getReturnType(); Class[] parameterTypes = method.getParameterTypes(); Type ffiReturnType = convertClassToFFI(returnType); Type[] ffiParameterTypes = new Type[parameterTypes.length]; for (int i = 0; i < ffiParameterTypes.length; ++i) { ffiParameterTypes[i] = convertClassToFFI(parameterTypes[i]); } final long address = library.getSymbolAddress(method.getName()); if (address == 0) { throw new UnsatisfiedLinkError(String.format("Could not locate '%s': %s", method.getName(), Library.getLastError())); } Function function = new Function(address, ffiReturnType, ffiParameterTypes); switch (invokerType) { case FastInt: return new FastIntMethodInvoker(library, function, returnType, parameterTypes); case FastLong: return new FastLongMethodInvoker(library, function, returnType, parameterTypes); case FastNumeric: return new FastNumericMethodInvoker(library, function, returnType, parameterTypes); case PointerArray: return new PointerArrayMethodInvoker(library, function, returnType, parameterTypes); case Default: return new DefaultMethodInvoker(library, function, returnType, parameterTypes); default: throw new RuntimeException("Unsupported InvokerType: " + invokerType); } } private static Type convertClassToFFI(Class type) { if (type == void.class || type == Void.class) { return Type.VOID; } else if (type == byte.class || type == Byte.class) { return Type.SINT8; } else if (type == short.class || type == Short.class) { return Type.SINT16; } else if (type == int.class || type == Integer.class) { return Type.SINT32; } else if (type == long.class || type == Long.class) { return Type.SINT64; } else if (type == float.class || type == Float.class) { return Type.FLOAT; } else if (type == double.class || type == Double.class) { return Type.DOUBLE; } else if (Address.class.isAssignableFrom(type)) { return Type.POINTER; } else { throw new IllegalArgumentException("Unknown type: " + type); } } private static interface MethodInvoker { public Object invoke(Object[] args); } private static final class DefaultMethodInvoker implements MethodInvoker { private final Library library; private final Function function; private final Class returnType; private final Class[] parameterTypes; public DefaultMethodInvoker(Library library, Function function, Class returnType, Class[] parameterTypes) { this.library = library; this.function = function; this.returnType = returnType; this.parameterTypes = parameterTypes; } public Object invoke(Object[] args) { HeapInvocationBuffer buffer = new HeapInvocationBuffer(function); for (int i = 0; i < args.length; ++i) { if (parameterTypes[i] == byte.class || parameterTypes[i] == Byte.class) { buffer.putByte(((Number) args[i]).intValue()); } else if (parameterTypes[i] == short.class || parameterTypes[i] == Short.class) { buffer.putShort(((Number) args[i]).intValue()); } else if (parameterTypes[i] == int.class || parameterTypes[i] == Integer.class) { buffer.putInt(((Number) args[i]).intValue()); } else if (parameterTypes[i] == long.class || parameterTypes[i] == Long.class) { buffer.putLong(((Number) args[i]).longValue()); } else if (parameterTypes[i] == float.class || parameterTypes[i] == Float.class) { buffer.putFloat(((Number) args[i]).floatValue()); } else if (parameterTypes[i] == double.class || parameterTypes[i] == Double.class) { buffer.putDouble(((Number) args[i]).doubleValue()); } else if (Address.class.isAssignableFrom(parameterTypes[i])) { buffer.putAddress(((Address) args[i]).address); } else { throw new RuntimeException("Unknown parameter type: " + parameterTypes[i]); } } Invoker invoker = Invoker.getInstance(); if (returnType == void.class || returnType == Void.class) { invoker.invokeInt(function, buffer); return null; } else if (returnType == byte.class || returnType == Byte.class) { return Byte.valueOf((byte) invoker.invokeInt(function, buffer)); } else if (returnType == short.class || returnType == Short.class) { return Short.valueOf((short) invoker.invokeInt(function, buffer)); } else if (returnType == int.class || returnType == Integer.class) { return Integer.valueOf(invoker.invokeInt(function, buffer)); } else if (returnType == long.class || returnType == Long.class) { return Long.valueOf(invoker.invokeLong(function, buffer)); } else if (returnType == float.class || returnType == Float.class) { return Float.valueOf(invoker.invokeFloat(function, buffer)); } else if (returnType == double.class || returnType == Double.class) { return Double.valueOf(invoker.invokeDouble(function, buffer)); } else if (Address.class.isAssignableFrom(returnType)) { return new Address(invoker.invokeAddress(function, buffer)); } throw new RuntimeException("Unknown return type: " + returnType); } } private static final Number convertResult(Class returnType, Number result) { if (returnType == void.class || returnType == Void.class) { return null; } else if (returnType == byte.class || returnType == Byte.class) { return result.byteValue(); } else if (returnType == short.class || returnType == Short.class) { return result.shortValue(); } else if (returnType == int.class || returnType == Integer.class) { return result.intValue(); } else if (returnType == long.class || returnType == Long.class) { return result.longValue(); } else if (returnType == float.class || returnType == Float.class) { return Float.intBitsToFloat(result.intValue()); } else if (returnType == double.class || returnType == Double.class) { return Double.longBitsToDouble(result.longValue()); } else if (Address.class.isAssignableFrom(returnType)) { return new Address(result.longValue()); } throw new RuntimeException("Unknown return type: " + returnType); } private static final class FastIntMethodInvoker implements MethodInvoker { private final Library library; private final Function function; private final Class returnType; private final Class[] parameterTypes; public FastIntMethodInvoker(Library library, Function function, Class returnType, Class[] parameterTypes) { this.library = library; this.function = function; this.returnType = returnType; this.parameterTypes = parameterTypes; } private static final boolean isFloat(Class c) { return Float.class.isAssignableFrom(c) || float.class == c; } private static final int i(Object value) { return value instanceof Float ? Float.floatToRawIntBits(((Float) value).floatValue()) : ((Number) value).intValue(); } public Object invoke(Object[] args) { final int result; switch (args.length) { case 0: if (isFloat(returnType)) { return Invoker.getInstance().invokeVrF(function); } result = Invoker.getInstance().invokeVrI(function); break; case 1: if (isFloat(returnType)) { return Invoker.getInstance().invokeIrF(function, i(args[0])); } result = Invoker.getInstance().invokeIrI(function, i(args[0])); break; case 2: if (isFloat(returnType)) { return Invoker.getInstance().invokeIIrF(function, i(args[0]), i(args[1])); } result = Invoker.getInstance().invokeIIrI(function, ((Number) args[0]).intValue(), ((Number) args[1]).intValue()); break; case 3: if (isFloat(returnType)) { return Invoker.getInstance().invokeIIIrF(function, i(args[0]), i(args[1]), i(args[2])); } result = Invoker.getInstance().invokeIIIrI(function, ((Number) args[0]).intValue(), ((Number) args[1]).intValue(), ((Number) args[2]).intValue()); break; default: throw new IndexOutOfBoundsException("fast-int invoker limited to 3 parameters"); } return convertResult(returnType, result); } } private static final class FastLongMethodInvoker implements MethodInvoker { private final Library library; private final Function function; private final Class returnType; private final Class[] parameterTypes; public FastLongMethodInvoker(Library library, Function function, Class returnType, Class[] parameterTypes) { this.library = library; this.function = function; this.returnType = returnType; this.parameterTypes = parameterTypes; } public Object invoke(Object[] args) { final long result; switch (args.length) { case 0: result = Invoker.getInstance().invokeVrL(function); break; case 1: result = Invoker.getInstance().invokeLrL(function, ((Number) args[0]).longValue()); break; case 2: result = Invoker.getInstance().invokeLLrL(function, ((Number) args[0]).longValue(), ((Number) args[1]).longValue()); break; case 3: result = Invoker.getInstance().invokeLLLrL(function, ((Number) args[0]).longValue(), ((Number) args[1]).longValue(), ((Number) args[2]).longValue()); break; default: throw new IndexOutOfBoundsException("fast-long invoker limited to 3 parameters"); } return convertResult(returnType, result); } } private static final class FastNumericMethodInvoker implements MethodInvoker { private final Library library; private final Function function; private final Class returnType; private final Class[] parameterTypes; public FastNumericMethodInvoker(Library library, Function function, Class returnType, Class[] parameterTypes) { this.library = library; this.function = function; this.returnType = returnType; this.parameterTypes = parameterTypes; } public Object invoke(Object[] args) { final long result; switch (args.length) { case 0: result = Invoker.getInstance().invokeVrN(function); break; case 1: result = Invoker.getInstance().invokeNrN(function, l(args[0])); break; case 2: result = Invoker.getInstance().invokeNNrN(function, l(args[0]), l(args[1])); break; case 3: result = Invoker.getInstance().invokeNNNrN(function, l(args[0]), l(args[1]), l(args[1])); break; default: throw new IndexOutOfBoundsException("fast-numeric invoker limited to 3 parameters"); } return convertResult(returnType, result); } private static final long l(Object arg) { if (arg instanceof Float) { return Float.floatToRawIntBits(((Float) arg).floatValue()); } else if (arg instanceof Double) { return Double.doubleToRawLongBits(((Double) arg).doubleValue()); } else { return ((Number) arg).longValue(); } } } private static final class PointerArrayMethodInvoker implements MethodInvoker { private static final MemoryIO Memory = MemoryIO.getInstance(); private final Library library; private final Function function; private final Class returnType; private final Class[] parameterTypes; public PointerArrayMethodInvoker(Library library, Function function, Class returnType, Class[] parameterTypes) { this.library = library; this.function = function; this.returnType = returnType; this.parameterTypes = parameterTypes; } private static final class MemoryHolder { private final long address; public MemoryHolder(long address) { this.address = address; } @Override protected void finalize() throws Throwable { MemoryIO.getInstance().freeMemory(address); } } private long getNativeLongReturnValue(long address) { return Platform.getPlatform().longSize() == 32 ? Memory.getInt(address) : Memory.getLong(address); } public Object invoke(Object[] args) { MemoryHolder[] memoryHolders = new MemoryHolder[function.getParameterCount()]; long[] parameterAddresses = new long[function.getParameterCount()]; for (int i = 0; i < parameterAddresses.length; ++i) { // Allocate 8 bytes; enough to store long long and double parameterAddresses[i] = Memory.allocateMemory(8, true); memoryHolders[i] = new MemoryHolder(parameterAddresses[i]); } for (int i = 0; i < args.length; ++i) { if (parameterTypes[i] == byte.class || parameterTypes[i] == Byte.class) { Memory.putByte(parameterAddresses[i], ((Number) args[i]).byteValue()); } else if (parameterTypes[i] == short.class || parameterTypes[i] == Short.class) { Memory.putShort(parameterAddresses[i], ((Number) args[i]).shortValue()); } else if (parameterTypes[i] == int.class || parameterTypes[i] == Integer.class) { Memory.putInt(parameterAddresses[i], ((Number) args[i]).intValue()); } else if (parameterTypes[i] == long.class || parameterTypes[i] == Long.class) { Memory.putLong(parameterAddresses[i], ((Number) args[i]).longValue()); } else if (parameterTypes[i] == float.class || parameterTypes[i] == Float.class) { Memory.putFloat(parameterAddresses[i], ((Number) args[i]).floatValue()); } else if (parameterTypes[i] == double.class || parameterTypes[i] == Double.class) { Memory.putDouble(parameterAddresses[i], ((Number) args[i]).doubleValue()); } else if (Address.class.isAssignableFrom(parameterTypes[i])) { Memory.putAddress(parameterAddresses[i], ((Address) args[i]).address); } else { throw new RuntimeException("Unknown parameter type: " + parameterTypes[i]); } } long returnBuffer = Memory.allocateMemory(8, true); try { Invoker.getInstance().invoke(function, returnBuffer, parameterAddresses); if (returnType == void.class || returnType == Void.class) { return null; } else if (returnType == byte.class || returnType == Byte.class) { return (byte) getNativeLongReturnValue(returnBuffer); } else if (returnType == short.class || returnType == Short.class) { return (short) getNativeLongReturnValue(returnBuffer); } else if (returnType == int.class || returnType == Integer.class) { return (int) getNativeLongReturnValue(returnBuffer); } else if (returnType == long.class || returnType == Long.class) { return Memory.getLong(returnBuffer); } else if (returnType == float.class || returnType == Float.class) { return Memory.getFloat(returnBuffer); } else if (returnType == double.class || returnType == Double.class) { return Memory.getDouble(returnBuffer); } else if (Address.class.isAssignableFrom(returnType)) { return new Address(Memory.getAddress(returnBuffer)); } throw new RuntimeException("Unknown return type: " + returnType); } finally { Memory.freeMemory(returnBuffer); } } } } jffi-1.0.2/test/com/kenai/jffi/ClosureTest.java0000644000175000017500000004756611424636215021275 0ustar twernertwerner package com.kenai.jffi; import com.kenai.jffi.UnitHelper.InvokerType; import com.kenai.jffi.UnitHelper.Address; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; import java.util.List; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; public class ClosureTest { private static interface LibClosureTest { void testClosureVrV(Address closure); byte testClosureVrB(Address closure); short testClosureVrS(Address closure); int testClosureVrI(Address closure); long testClosureVrL(Address closure); float testClosureVrF(Address closure); double testClosureVrD(Address closure); void testClosureTrV(Address closure, Address struct); void testClosureBrV(Address closure, byte value); void testClosureSrV(Address closure, short value); void testClosureIrV(Address closure, int value); void testClosureLrV(Address closure, long value); void testClosureFrV(Address closure, float value); void testClosureDrV(Address closure, double value); } private LibClosureTest lib, fastint, fastlong, fastnum; public ClosureTest() { } @BeforeClass public static void setUpClass() throws Exception { } @AfterClass public static void tearDownClass() throws Exception { } @Before public void setUp() { lib = UnitHelper.loadTestLibrary(LibClosureTest.class, InvokerType.Default); fastlong = UnitHelper.loadTestLibrary(LibClosureTest.class, InvokerType.FastLong); fastnum = UnitHelper.loadTestLibrary(LibClosureTest.class, InvokerType.FastNumeric); fastint = Platform.getPlatform().addressSize() == 32 ? UnitHelper.loadTestLibrary(LibClosureTest.class, InvokerType.FastInt) : fastlong; } @After public void tearDown() { } // TODO add test methods here. // The methods must be annotated with annotation @Test. For example: // // @Test // public void hello() {} private void testClosureVrV(LibClosureTest lib) { final boolean called[] = { false }; Closure closure = new Closure() { public void invoke(Buffer buffer) { called[0] = true; } }; Closure.Handle handle = ClosureManager.getInstance().newClosure(closure, Type.VOID, new Type[0], CallingConvention.DEFAULT); lib.testClosureVrV(new Address(handle)); assertTrue("Closure not called", called[0]); } @Test public void defaultClosureVrV() throws Throwable { testClosureVrV(lib); } @Test public void fastIntClosureVrV() throws Throwable { if (Platform.getPlatform().addressSize() == 32) { testClosureVrV(fastint); } } @Test public void fastLongClosureVrV() throws Throwable { testClosureVrV(fastlong); } private void testClosureVrB(LibClosureTest lib) { final boolean called[] = { false }; final byte MAGIC = (byte) 0x12; Closure closure = new Closure() { public void invoke(Buffer buffer) { called[0] = true; buffer.setByteReturn(MAGIC); } }; Closure.Handle handle = ClosureManager.getInstance().newClosure(closure, Type.SINT8, new Type[0], CallingConvention.DEFAULT); byte retval = lib.testClosureVrB(new Address(handle)); assertTrue("Closure not called", called[0]); assertEquals("Wrong value returned by closure", MAGIC, retval); } @Test public void defaultClosureVrB() throws Throwable { testClosureVrB(lib); } @Test public void fastIntClosureVrB() throws Throwable { testClosureVrB(fastint); } @Test public void fastLongClosureVrB() throws Throwable { testClosureVrB(fastlong); } private void testClosureVrS(LibClosureTest lib) { final boolean called[] = { false }; final short MAGIC = (byte) 0x1234; Closure closure = new Closure() { public void invoke(Buffer buffer) { called[0] = true; buffer.setShortReturn(MAGIC); } }; Closure.Handle handle = ClosureManager.getInstance().newClosure(closure, Type.SINT32, new Type[0], CallingConvention.DEFAULT); short retval = lib.testClosureVrS(new Address(handle)); assertTrue("Closure not called", called[0]); assertEquals("Wrong value returned by closure", MAGIC, retval); } @Test public void defaultClosureVrS() throws Throwable { testClosureVrS(lib); } @Test public void fastIntClosureVrS() throws Throwable { testClosureVrS(fastint); } @Test public void fastLongClosureVrS() throws Throwable { testClosureVrS(fastlong); } private void testClosureVrI(LibClosureTest lib) { final boolean called[] = { false }; final int MAGIC = 0x12345678; Closure closure = new Closure() { public void invoke(Buffer buffer) { called[0] = true; buffer.setIntReturn(MAGIC); } }; Closure.Handle handle = ClosureManager.getInstance().newClosure(closure, Type.SINT64, new Type[0], CallingConvention.DEFAULT); int retval = lib.testClosureVrI(new Address(handle)); assertTrue("Closure not called", called[0]); assertEquals("Wrong value returned by closure", MAGIC, retval); } @Test public void defaultClosureVrI() throws Throwable { testClosureVrI(lib); } @Test public void fastIntClosureVrI() throws Throwable { testClosureVrI(fastint); } @Test public void fastLongClosureVrI() throws Throwable { testClosureVrI(fastlong); } private void testClosureVrL(LibClosureTest lib) { final boolean called[] = { false }; final long MAGIC = 0x12345678cafebabeL; Closure closure = new Closure() { public void invoke(Buffer buffer) { called[0] = true; buffer.setLongReturn(MAGIC); } }; Closure.Handle handle = ClosureManager.getInstance().newClosure(closure, Type.SINT64, new Type[0], CallingConvention.DEFAULT); long retval = lib.testClosureVrL(new Address(handle)); assertTrue("Closure not called", called[0]); assertEquals("Wrong value returned by closure", MAGIC, retval); } @Test public void defaultClosureVrL() throws Throwable { testClosureVrL(lib); } @Test public void fastLongClosureVrL() throws Throwable { testClosureVrL(fastlong); } private void testClosureVrF(LibClosureTest lib) { final boolean called[] = { false }; final float MAGIC = (float) 0x12345678; Closure closure = new Closure() { public void invoke(Buffer buffer) { called[0] = true; buffer.setFloatReturn(MAGIC); } }; Closure.Handle handle = ClosureManager.getInstance().newClosure(closure, Type.FLOAT, new Type[0], CallingConvention.DEFAULT); float retval = lib.testClosureVrF(new Address(handle)); assertTrue("Closure not called", called[0]); assertTrue("Wrong value returned by closure", (MAGIC -retval) < 0.0001); } @Test public void defaultClosureVrF() throws Throwable { testClosureVrF(lib); } @Test public void fastNumericClosureVrF() throws Throwable { testClosureVrF(fastnum); } private void testClosureVrD(LibClosureTest lib) { final boolean called[] = { false }; final double MAGIC = (double) 0x12345678; Closure closure = new Closure() { public void invoke(Buffer buffer) { called[0] = true; buffer.setDoubleReturn(MAGIC); } }; Closure.Handle handle = ClosureManager.getInstance().newClosure(closure, Type.DOUBLE, new Type[0], CallingConvention.DEFAULT); double retval = lib.testClosureVrD(new Address(handle)); assertTrue("Closure not called", called[0]); assertTrue("Wrong value returned by closure", (MAGIC -retval) < 0.0001); } @Test public void defaultClosureVrD() throws Throwable { testClosureVrD(lib); } @Test public void fastNumericClosureVrD() throws Throwable { testClosureVrD(fastnum); } @Test public void testClosureTrV() throws Throwable { final boolean called[] = { false }; final byte[] s8 = { 0 }; final float[] f32 = { 0 }; final int[] s32 = { 0 }; final byte S8_MAGIC = (byte) 0xfe; final int S32_MAGIC = (int) 0xdeadbeef; final float F32_MAGIC = (float) 0x12345678; Closure closure = new Closure() { public void invoke(Buffer buffer) { called[0] = true; long struct = buffer.getStruct(0); s8[0] = MemoryIO.getInstance().getByte(struct); f32[0] = MemoryIO.getInstance().getFloat(struct + 4); s32[0] = MemoryIO.getInstance().getInt(struct + 8); } }; Struct s8f32s32 = new Struct(new Type[] { Type.SINT8, Type.FLOAT, Type.SINT32 }); Closure.Handle handle = ClosureManager.getInstance().newClosure(closure, Type.VOID, new Type[] { s8f32s32, Type.POINTER }, CallingConvention.DEFAULT); long struct = MemoryIO.getInstance().allocateMemory(12, true); MemoryIO.getInstance().putByte(struct, S8_MAGIC); MemoryIO.getInstance().putFloat(struct + 4, F32_MAGIC); MemoryIO.getInstance().putInt(struct + 8, S32_MAGIC); lib.testClosureTrV(new Address(handle), new Address(struct)); assertTrue("Closure not called", called[0]); assertEquals("Wrong s8 field value", S8_MAGIC, s8[0]); assertEquals("Wrong s32 field value", S32_MAGIC, s32[0]); assertTrue("Wrong f32 field value", (F32_MAGIC - f32[0]) < 0.0001); } @Test public void testClosureVrTFromArray() throws Throwable { final boolean called[] = { false }; final byte S8_MAGIC = (byte) 0xfe; final int S32_MAGIC = (int) 0xdeadbeef; final float F32_MAGIC = (float) 0x12345678; Closure closure = new Closure() { public void invoke(Buffer buffer) { called[0] = true; ByteBuffer retVal = ByteBuffer.allocate(12).order(ByteOrder.nativeOrder()); retVal.put(0, S8_MAGIC); retVal.putFloat(4, F32_MAGIC); retVal.putInt(8, S32_MAGIC); buffer.setStructReturn(retVal.array(), retVal.arrayOffset()); } }; Struct s8f32s32 = new Struct(new Type[] { Type.SINT8, Type.FLOAT, Type.SINT32 }); Closure.Handle handle = ClosureManager.getInstance().newClosure(closure, s8f32s32, new Type[] { }, CallingConvention.DEFAULT); Function f = new Function(UnitHelper.findSymbol("testClosureVrT").address, s8f32s32, new Type[] { Type.POINTER }); HeapInvocationBuffer paramBuffer = new HeapInvocationBuffer(f); paramBuffer.putAddress(handle.getAddress()); ByteBuffer retval = ByteBuffer.wrap(Invoker.getInstance().invokeStruct(f, paramBuffer)); retval.order(ByteOrder.nativeOrder()); assertTrue("Closure not called", called[0]); assertEquals("Wrong s8 field value", S8_MAGIC, retval.get(0)); assertEquals("Wrong s32 field value", S32_MAGIC, retval.getInt(8)); assertTrue("Wrong f32 field value", (F32_MAGIC - retval.getFloat(4)) < 0.0001); } @Test public void testClosureVrTFromPointer() throws Throwable { final boolean called[] = { false }; final byte S8_MAGIC = (byte) 0xfe; final int S32_MAGIC = (int) 0xdeadbeef; final float F32_MAGIC = (float) 0x12345678; Closure closure = new Closure() { public void invoke(Buffer buffer) { called[0] = true; long struct = MemoryIO.getInstance().allocateMemory(12, true); MemoryIO.getInstance().putByte(struct, S8_MAGIC); MemoryIO.getInstance().putFloat(struct + 4, F32_MAGIC); MemoryIO.getInstance().putInt(struct + 8, S32_MAGIC); buffer.setStructReturn(struct); } }; Struct s8f32s32 = new Struct(new Type[] { Type.SINT8, Type.FLOAT, Type.SINT32 }); Closure.Handle handle = ClosureManager.getInstance().newClosure(closure, s8f32s32, new Type[] { }, CallingConvention.DEFAULT); Function f = new Function(UnitHelper.findSymbol("testClosureVrT").address, s8f32s32, new Type[] { Type.POINTER }); HeapInvocationBuffer paramBuffer = new HeapInvocationBuffer(f); paramBuffer.putAddress(handle.getAddress()); ByteBuffer retval = ByteBuffer.wrap(Invoker.getInstance().invokeStruct(f, paramBuffer)); retval.order(ByteOrder.nativeOrder()); assertTrue("Closure not called", called[0]); assertEquals("Wrong s8 field value", S8_MAGIC, retval.get(0)); assertEquals("Wrong s32 field value", S32_MAGIC, retval.getInt(8)); assertTrue("Wrong f32 field value", (F32_MAGIC - retval.getFloat(4)) < 0.0001); } private void testClosureBrV(LibClosureTest lib) { final boolean called[] = { false }; final byte MAGIC = (byte) 0x12; final byte[] data = { 0 }; Closure closure = new Closure() { public void invoke(Buffer buffer) { called[0] = true; data[0] = buffer.getByte(0); } }; Closure.Handle handle = ClosureManager.getInstance().newClosure(closure, Type.VOID, new Type[] { Type.SINT8 }, CallingConvention.DEFAULT); lib.testClosureBrV(new Address(handle), MAGIC); assertTrue("Closure not called", called[0]); assertEquals("Wrong value passed to closure", MAGIC, data[0]); } @Test public void defaultClosureBrV() throws Throwable { testClosureBrV(lib); } @Test public void fastIntClosureBrV() throws Throwable { testClosureBrV(fastint); } @Test public void fastLongClosureBrV() throws Throwable { testClosureBrV(fastlong); } private void testClosureSrV(LibClosureTest lib) { final boolean called[] = { false }; final short MAGIC = (byte) 0x1234; final short[] data = { 0 }; Closure closure = new Closure() { public void invoke(Buffer buffer) { called[0] = true; data[0] = buffer.getShort(0); } }; Closure.Handle handle = ClosureManager.getInstance().newClosure(closure, Type.VOID, new Type[] { Type.SINT16 }, CallingConvention.DEFAULT); lib.testClosureSrV(new Address(handle), MAGIC); assertTrue("Closure not called", called[0]); assertEquals("Wrong value passed to closure", MAGIC, data[0]); } @Test public void defaultClosureSrV() throws Throwable { testClosureSrV(lib); } @Test public void fastIntClosureSrV() throws Throwable { testClosureSrV(fastint); } @Test public void fastLongClosureSrV() throws Throwable { testClosureSrV(fastlong); } private void testClosureIrV(LibClosureTest lib) { final boolean called[] = { false }; final int MAGIC = 0x12345678; final int[] data = { 0 }; Closure closure = new Closure() { public void invoke(Buffer buffer) { called[0] = true; data[0] = buffer.getInt(0); } }; Closure.Handle handle = ClosureManager.getInstance().newClosure(closure, Type.VOID, new Type[] { Type.SINT32 }, CallingConvention.DEFAULT); lib.testClosureIrV(new Address(handle), MAGIC); assertTrue("Closure not called", called[0]); assertEquals("Wrong value passed to closure", MAGIC, data[0]); } @Test public void defaultClosureIrV() throws Throwable { testClosureIrV(lib); } @Test public void fastIntClosureIrV() throws Throwable { testClosureIrV(fastint); } @Test public void fastLongClosureIrV() throws Throwable { testClosureIrV(fastlong); } private void testClosureLrV(LibClosureTest lib) { final boolean called[] = { false }; final long MAGIC = 0x12345678fee1deadL; final long[] data = { 0 }; Closure closure = new Closure() { public void invoke(Buffer buffer) { called[0] = true; data[0] = buffer.getLong(0); } }; Closure.Handle handle = ClosureManager.getInstance().newClosure(closure, Type.VOID, new Type[] { Type.SINT64 }, CallingConvention.DEFAULT); lib.testClosureLrV(new Address(handle), MAGIC); assertTrue("Closure not called", called[0]); assertEquals("Wrong value passed to closure", MAGIC, data[0]); } @Test public void defaultClosureLrV() throws Throwable { testClosureLrV(lib); } @Test public void fastLongClosureLrV() throws Throwable { testClosureLrV(fastlong); } private void testClosureFrV(LibClosureTest lib) { final boolean called[] = { false }; final float MAGIC = (float) 0x12345678; final float[] data = { 0 }; Closure closure = new Closure() { public void invoke(Buffer buffer) { called[0] = true; data[0] = buffer.getFloat(0); } }; Closure.Handle handle = ClosureManager.getInstance().newClosure(closure, Type.VOID, new Type[] { Type.FLOAT }, CallingConvention.DEFAULT); lib.testClosureFrV(new Address(handle), MAGIC); assertTrue("Closure not called", called[0]); assertTrue("Wrong value passed to closure", (MAGIC - data[0]) < 0.0001); } @Test public void defaultClosureFrV() throws Throwable { testClosureFrV(lib); } private void testClosureDrV(LibClosureTest lib) { final boolean called[] = { false }; final double MAGIC = (double) 0x12345678; final double[] data = { 0 }; Closure closure = new Closure() { public void invoke(Buffer buffer) { called[0] = true; data[0] = buffer.getDouble(0); } }; Closure.Handle handle = ClosureManager.getInstance().newClosure(closure, Type.VOID, new Type[] { Type.DOUBLE }, CallingConvention.DEFAULT); lib.testClosureDrV(new Address(handle), MAGIC); assertTrue("Closure not called", called[0]); assertTrue("Wrong value passed to closure", (MAGIC - data[0]) < 0.0001); } @Test public void defaultClosureDrV() throws Throwable { testClosureDrV(lib); } @Test public void allocateLots() throws Throwable { ClosureManager m = ClosureManager.getInstance(); List handles = new ArrayList(); for (int i = 0; i < 1000; ++i) { Closure c = new Closure() { public void invoke(Buffer buffer) { throw new UnsupportedOperationException("Not supported yet."); } }; handles.add(m.newClosure(c, Type.FLOAT, new Type[0], CallingConvention.DEFAULT)); } for (Closure.Handle h : handles) { h.dispose(); } handles.clear(); for (int i = 0; i < 1000; ++i) { Closure c = new Closure() { public void invoke(Buffer buffer) { throw new UnsupportedOperationException("Not supported yet."); } }; handles.add(m.newClosure(c, Type.FLOAT, new Type[0], CallingConvention.DEFAULT)); } } static class Proxy { public void invoke(long retval, long args) { } } } jffi-1.0.2/test/com/kenai/jffi/MemoryTest.java0000644000175000017500000000461011424636215021110 0ustar twernertwerner package com.kenai.jffi; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; public class MemoryTest { public MemoryTest() { } @BeforeClass public static void setUpClass() throws Exception { } @AfterClass public static void tearDownClass() throws Exception { } @Before public void setUp() { } @After public void tearDown() { } // TODO add test methods here. // The methods must be annotated with annotation @Test. For example: // // @Test // public void hello() {} @Test public void allocateUnaligned() { long memory = MemoryIO.getInstance().allocateMemory(1024, false); assertNotSame("Could not allocate memory", 0L, memory); MemoryIO.getInstance().freeMemory(memory); } @Test public void zeroTerminatedByteArray() { byte[] MAGIC = { 't', 'e', 's', 't' }; long memory = MemoryIO.getInstance().allocateMemory(MAGIC.length + 1, true); MemoryIO.getInstance().putByteArray(memory, MAGIC, 0, MAGIC.length); byte[] string = MemoryIO.getInstance().getZeroTerminatedByteArray(memory); assertArrayEquals(MAGIC, string); } @Test public void zeroTerminatedByteArrayWithLength() { byte[] MAGIC = { 't', 'e', 's', 't' }; long memory = MemoryIO.getInstance().allocateMemory(MAGIC.length + 1, true); MemoryIO.getInstance().putByteArray(memory, MAGIC, 0, MAGIC.length); MemoryIO.getInstance().putByte(memory + 4, (byte) 0xff); byte[] string = MemoryIO.getInstance().getZeroTerminatedByteArray(memory, 4); assertArrayEquals(MAGIC, string); } @Test public void putZeroTerminatedByteArray() { final byte[] DIRTY = { 'd', 'i', 'r', 't', 'y' }; final byte[] MAGIC = { 't', 'e', 's', 't' }; long memory = MemoryIO.getInstance().allocateMemory(MAGIC.length + 1, true); MemoryIO.getInstance().putByteArray(memory, DIRTY, 0, DIRTY.length); MemoryIO.getInstance().putZeroTerminatedByteArray(memory, MAGIC, 0, MAGIC.length); assertArrayEquals("String not written to native memory", MAGIC, MemoryIO.getInstance().getZeroTerminatedByteArray(memory, 4)); assertEquals("String not NUL terminated", (byte)0, MemoryIO.getInstance().getByte(memory + 4)); } }jffi-1.0.2/test/com/kenai/jffi/StructTest.java0000644000175000017500000002435611424636215021135 0ustar twernertwerner package com.kenai.jffi; import com.kenai.jffi.UnitHelper.Address; import java.nio.ByteBuffer; import java.nio.ByteOrder; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; /** * Tests C struct parameters and return values using pass/return by value. */ public class StructTest { public StructTest() { } @BeforeClass public static void setUpClass() throws Exception { } @AfterClass public static void tearDownClass() throws Exception { } @Before public void setUp() { } @After public void tearDown() { } // TODO add test methods here. // The methods must be annotated with annotation @Test. For example: // // @Test // public void hello() {} // // struct { char c; }; // @Test public void s8UsingForeign() throws Throwable { Foreign foreign = Foreign.getInstance(); long sint8 = foreign.lookupBuiltinType(Foreign.TYPE_SINT8); long struct = foreign.newStruct(new long[] { sint8 }, false); assertEquals("Incorrect size", 1, foreign.getTypeSize(struct)); assertEquals("Incorrect alignment", 1, foreign.getTypeAlign(struct)); } @Test public void s8UsingStruct() throws Throwable { Struct s8 = new Struct(Type.SINT8); assertEquals("Incorrect size", 1, s8.size()); assertEquals("Incorrect alignment", 1, s8.alignment()); } // // struct { char c; int i; }; // @Test public void s8s32UsingForeign() throws Throwable { Foreign foreign = Foreign.getInstance(); long sint8 = foreign.lookupBuiltinType(Foreign.TYPE_SINT8); long sint32 = foreign.lookupBuiltinType(Foreign.TYPE_SINT32); long struct = foreign.newStruct(new long[] { sint8, sint32 }, false); assertEquals("Incorrect size", 8, foreign.getTypeSize(struct)); assertEquals("Incorrect alignment", 4, foreign.getTypeAlign(struct)); } @Test public void s8s32UsingStruct() throws Throwable { Struct s8s32 = new Struct(Type.SINT8, Type.SINT32); assertEquals("Incorrect size", 8, s8s32.size()); assertEquals("Incorrect alignment", 4, s8s32.alignment()); } @Test public void s8s32ReturnWithDefaultBuffer() throws Throwable { Struct s8s32 = new Struct(Type.SINT8, Type.SINT32); Address sym = UnitHelper.findSymbol("struct_return_s8s32"); Function f = new Function(sym.address, s8s32/*, new Type[0]*/); byte[] returnBuffer = Invoker.getInstance().invokeStruct(f, new HeapInvocationBuffer(f)); ByteBuffer buf = ByteBuffer.wrap(returnBuffer).order(ByteOrder.nativeOrder()); assertEquals("Wrong s8 value", (byte) 0x7f, buf.get(0)); assertEquals("Wrong s32 value", 0x12345678, buf.getInt(4)); } @Test public void s8s32ReturnWithProvidedBuffer() throws Throwable { Struct s8s32 = new Struct(Type.SINT8, Type.SINT32); Address sym = UnitHelper.findSymbol("struct_return_s8s32"); Function f = new Function(sym.address, s8s32/*, new Type[0]*/); byte[] returnBuffer = new byte[s8s32.size()]; Invoker.getInstance().invokeStruct(f, new HeapInvocationBuffer(f), returnBuffer, 0); ByteBuffer buf = ByteBuffer.wrap(returnBuffer).order(ByteOrder.nativeOrder()); assertEquals("Wrong s8 value", (byte) 0x7f, buf.get(0)); assertEquals("Wrong s32 value", 0x12345678, buf.getInt(4)); } @Test public void s8s32ReturnWithProvidedBufferAndOffset() throws Throwable { Struct s8s32 = new Struct(Type.SINT8, Type.SINT32); Address sym = UnitHelper.findSymbol("struct_return_s8s32"); Function f = new Function(sym.address, s8s32, new Type[0]); int adj = 8; byte[] returnBuffer = new byte[adj + s8s32.size()]; Invoker.getInstance().invokeStruct(f, new HeapInvocationBuffer(f), returnBuffer, adj); ByteBuffer buf = ByteBuffer.wrap(returnBuffer, adj, s8s32.size()).slice().order(ByteOrder.nativeOrder()); assertEquals("Wrong s8 value", (byte) 0x7f, buf.get(0)); assertEquals("Wrong s32 value", 0x12345678, buf.getInt(4)); } @Test public void structS8S32ParameterFromArray() throws Throwable { Address sym_s8 = UnitHelper.findSymbol("struct_s8s32_get_s8"); Address sym_s32 = UnitHelper.findSymbol("struct_s8s32_get_s32"); Struct s8s32 = new Struct(Type.SINT8, Type.SINT32); Function get_s8 = new Function(sym_s8.address, Type.SINT32, s8s32 ); Function get_s32 = new Function(sym_s32.address, Type.SINT32, s8s32); HeapInvocationBuffer paramBuffer = new HeapInvocationBuffer(get_s8); ByteBuffer buf = ByteBuffer.allocate(s8s32.size()).order(ByteOrder.nativeOrder()); buf.put(0, (byte) 0x12); buf.putInt(4, 0x87654321); paramBuffer.putStruct(buf.array(), buf.arrayOffset()); assertEquals("Wrong s8 value", 0x12, Invoker.getInstance().invokeInt(get_s8, paramBuffer)); assertEquals("Wrong s32 value", 0x87654321, Invoker.getInstance().invokeInt(get_s32, paramBuffer)); } @Test public void structS8S32ParameterFromPointer() throws Throwable { Address sym_s8 = UnitHelper.findSymbol("struct_s8s32_get_s8"); Address sym_s32 = UnitHelper.findSymbol("struct_s8s32_get_s32"); Struct s8s32 = new Struct(Type.SINT8, Type.SINT32); Function get_s8 = new Function(sym_s8.address, Type.SINT32, s8s32); Function get_s32 = new Function(sym_s32.address, Type.SINT32, s8s32); HeapInvocationBuffer paramBuffer = new HeapInvocationBuffer(get_s8); long struct = MemoryIO.getInstance().allocateMemory(s8s32.size(), true); MemoryIO.getInstance().putByte(struct, (byte) 0x12); MemoryIO.getInstance().putInt(struct + 4, 0x87654321); paramBuffer.putStruct(struct); assertEquals("Wrong s8 value", 0x12, Invoker.getInstance().invokeInt(get_s8, paramBuffer)); assertEquals("Wrong s32 value", 0x87654321, Invoker.getInstance().invokeInt(get_s32, paramBuffer)); } @Test public void structS8S32ParameterFromArrayAndS32() throws Throwable { Address sym = UnitHelper.findSymbol("struct_s8s32_s32_ret_s32"); Struct s8s32 = new Struct(Type.SINT8, Type.SINT32); Function function = new Function(sym.address, Type.SINT32, s8s32, Type.SINT32); HeapInvocationBuffer paramBuffer = new HeapInvocationBuffer(function); ByteBuffer buf = ByteBuffer.allocate(s8s32.size()).order(ByteOrder.nativeOrder()); buf.put(0, (byte) 0x12); buf.putInt(4, 0x87654321); paramBuffer.putStruct(buf.array(), buf.arrayOffset()); paramBuffer.putInt(0xdeadbeef); int retval = Invoker.getInstance().invokeInt(function, paramBuffer); assertEquals("Wrong s32 param value", (int) 0xdeadbeef, retval); } @Test public void structS8S32ParameterFromPointerAndS32() throws Throwable { Address sym = UnitHelper.findSymbol("struct_s8s32_s32_ret_s32"); Struct s8s32 = new Struct(Type.SINT8, Type.SINT32); Function function = new Function(sym.address, Type.SINT32, s8s32, Type.SINT32); HeapInvocationBuffer paramBuffer = new HeapInvocationBuffer(function); long struct = MemoryIO.getInstance().allocateMemory(s8s32.size(), true); MemoryIO.getInstance().putByte(struct, (byte) 0x12); MemoryIO.getInstance().putInt(struct + 4, 0x87654321); paramBuffer.putStruct(struct); // Add a following int32 param and ensure it is passed paramBuffer.putInt(0xdeadbeef); int retval = Invoker.getInstance().invokeInt(function, paramBuffer); assertEquals("Wrong s32 param value", (int) 0xdeadbeef, retval); } @Test public void structS8S32ParameterFromArrayAndS64() throws Throwable { Address sym = UnitHelper.findSymbol("struct_s8s32_s64_ret_s64"); Struct s8s32 = new Struct(Type.SINT8, Type.SINT32); Function function = new Function(sym.address, Type.SINT64, s8s32, Type.SINT64); HeapInvocationBuffer paramBuffer = new HeapInvocationBuffer(function); ByteBuffer buf = ByteBuffer.allocate(s8s32.size()).order(ByteOrder.nativeOrder()); buf.put(0, (byte) 0x12); buf.putInt(4, 0x87654321); paramBuffer.putStruct(buf.array(), buf.arrayOffset()); paramBuffer.putLong(0xdeadbeef); long retval = Invoker.getInstance().invokeLong(function, paramBuffer); assertEquals("Wrong s64 param value", 0xdeadbeef, retval); } @Test public void structS8S32ParameterFromPointerAndS64() throws Throwable { Address sym = UnitHelper.findSymbol("struct_s8s32_s64_ret_s64"); Struct s8s32 = new Struct(new Type[] { Type.SINT8, Type.SINT32 }); Function function = new Function(sym.address, Type.SINT64, s8s32, Type.SINT64); long struct = MemoryIO.getInstance().allocateMemory(s8s32.size(), true); MemoryIO.getInstance().putByte(struct, (byte) 0x12); MemoryIO.getInstance().putInt(struct + 4, 0x87654321); HeapInvocationBuffer paramBuffer = new HeapInvocationBuffer(function); paramBuffer.putStruct(struct); // Add a following int64 param and ensure it is passed paramBuffer.putLong(0xdeadbeef); long retval = Invoker.getInstance().invokeLong(function, paramBuffer); assertEquals("Wrong s64 param value", 0xdeadbeef, retval); } @Test public void s8s32_set() throws Throwable { Address sym = UnitHelper.findSymbol("struct_s8s32_set"); Struct s8s32 = new Struct(Type.SINT8, Type.SINT32); Function function = new Function(sym.address, s8s32, Type.SINT8, Type.SINT32); HeapInvocationBuffer paramBuffer = new HeapInvocationBuffer(function); paramBuffer.putByte((byte) 0x12); paramBuffer.putInt(0x87654321); byte[] returnBuffer = Invoker.getInstance().invokeStruct(function, paramBuffer); ByteBuffer buf = ByteBuffer.wrap(returnBuffer).order(ByteOrder.nativeOrder()); assertEquals("Wrong s8 value", (byte) 0x12, buf.get(0)); assertEquals("Wrong s32 value", 0x87654321, buf.getInt(4)); } } jffi-1.0.2/test/com/kenai/jffi/PlatformTest.java0000644000175000017500000000153511424636215021427 0ustar twernertwerner package com.kenai.jffi; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; /** * Tests the Platform class */ public class PlatformTest { public PlatformTest() { } @BeforeClass public static void setUpClass() throws Exception { } @AfterClass public static void tearDownClass() throws Exception { } @Before public void setUp() { } @After public void tearDown() { } // TODO add test methods here. // The methods must be annotated with annotation @Test. For example: // // @Test // public void hello() {} @Test public void isSupported() { // This should never fail assertTrue("isSupported failed", Platform.getPlatform().isSupported()); } }jffi-1.0.2/test/com/kenai/jffi/NumberTest.java0000644000175000017500000002145011424636215021071 0ustar twernertwerner package com.kenai.jffi; import com.kenai.jffi.UnitHelper.InvokerType; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; public class NumberTest { private static interface LibNumberTest { byte ret_s8(byte v); byte ret_u8(byte v); short ret_s16(short v); short ret_u16(short v); int ret_s32(int v); int ret_u32(int v); long ret_s64(long v); long ret_u64(long v); float ret_float(float v); double ret_double(double v); } private static interface LibM { float powf(float x, float y); float cosf(float x); } public NumberTest() { } @BeforeClass public static void setUpClass() throws Exception { } @AfterClass public static void tearDownClass() throws Exception { } @Before public void setUp() { } @After public void tearDown() { } private static final byte[] s8_values = { 0, Byte.MAX_VALUE, Byte.MIN_VALUE, -1 }; private static final byte[] u8_values = { 0, Byte.MAX_VALUE, (byte) 0x80, (byte) 0xff }; private static final short[] s16_values = { 0, Short.MAX_VALUE, Short.MIN_VALUE, -1 }; private static final short[] u16_values = { 0, Short.MAX_VALUE, (short) 0x8000, (short) 0xffff }; private static final int[] s32_values = { 0, Integer.MAX_VALUE, Integer.MIN_VALUE, -1 }; private static final int[] u32_values = { 0, Integer.MAX_VALUE, 0x80000000, 0xffffffff }; private static final long[] s64_values = { 0, Long.MAX_VALUE, Long.MIN_VALUE, -1 }; private static final long[] u64_values = { 0, Long.MAX_VALUE, 0x8000000000000000L, 0xffffffffffffffffL }; @Test public void returnS8() { returnS8(InvokerType.Default); } @Test public void returnU8() { returnU8(InvokerType.Default); } @Test public void returnFastIntS8() { returnS8(InvokerType.FastInt); } @Test public void returnFastIntU8() { returnU8(InvokerType.FastInt); } @Test public void returnFastLongS8() { returnS8(InvokerType.FastLong); } @Test public void returnFastLongU8() { returnU8(InvokerType.FastLong); } @Test public void returnFastNumericS8() { returnS8(InvokerType.FastNumeric); } @Test public void returnFastNumericU8() { returnU8(InvokerType.FastNumeric); } @Test public void returnPointerArrayS8() { returnS8(InvokerType.PointerArray); } @Test public void returnPointerArrayU8() { returnU8(InvokerType.PointerArray); } private void returnS8(InvokerType type) { LibNumberTest lib = UnitHelper.loadTestLibrary(LibNumberTest.class, type); for (int i = 0; i < s8_values.length; ++i) { assertEquals("Value not returned correctly", s8_values[i], lib.ret_s8(s8_values[i])); } } private void returnU8(InvokerType type) { LibNumberTest lib = UnitHelper.loadTestLibrary(LibNumberTest.class, type); for (int i = 0; i < u8_values.length; ++i) { assertEquals("Value not returned correctly", u8_values[i], lib.ret_u8(u8_values[i])); } } @Test public void returnS16() { returnS16(InvokerType.Default); } @Test public void returnFastIntS16() { returnS16(InvokerType.FastInt); } @Test public void returnFastLongS16() { returnS16(InvokerType.FastLong); } @Test public void returnFastNumericS16() { returnS16(InvokerType.FastNumeric); } @Test public void returnPointerArrayS16() { returnS16(InvokerType.PointerArray); } private void returnS16(InvokerType type) { LibNumberTest lib = UnitHelper.loadTestLibrary(LibNumberTest.class, type); for (int i = 0; i < s16_values.length; ++i) { assertEquals("Value not returned correctly", s16_values[i], lib.ret_s16(s16_values[i])); } } @Test public void returnU16() { returnU16(InvokerType.Default); } @Test public void returnFastIntU16() { returnU16(InvokerType.FastInt); } @Test public void returnFastLongU16() { returnU16(InvokerType.FastLong); } @Test public void returnFastNumericU16() { returnU16(InvokerType.FastNumeric); } @Test public void returnPointerArrayU16() { returnU16(InvokerType.PointerArray); } private void returnU16(InvokerType type) { LibNumberTest lib = UnitHelper.loadTestLibrary(LibNumberTest.class, type); for (int i = 0; i < u16_values.length; ++i) { assertEquals("Value not returned correctly", u16_values[i], lib.ret_u16(u16_values[i])); } } @Test public void returnS32() { returnS32(InvokerType.Default); } @Test public void returnFastintS32() { returnS32(InvokerType.FastInt); } @Test public void returnFastLongS32() { returnS32(InvokerType.FastLong); } @Test public void returnFastNumericS32() { returnS32(InvokerType.FastNumeric); } @Test public void returnPointerArrayS32() { returnS32(InvokerType.PointerArray); } private void returnS32(InvokerType type) { LibNumberTest lib = UnitHelper.loadTestLibrary(LibNumberTest.class, type); for (int i = 0; i < s32_values.length; ++i) { assertEquals("Value not returned correctly", s32_values[i], lib.ret_s32(s32_values[i])); } } @Test public void returnU32() { returnU32(InvokerType.Default); } @Test public void returnFastintU32() { returnU32(InvokerType.FastInt); } @Test public void returnFastLongU32() { returnU32(InvokerType.FastLong); } @Test public void returnFastNumericU32() { returnU32(InvokerType.FastNumeric); } @Test public void returnPointerArrayU32() { returnU32(InvokerType.PointerArray); } private void returnU32(InvokerType type) { LibNumberTest lib = UnitHelper.loadTestLibrary(LibNumberTest.class, type); for (int i = 0; i < u32_values.length; ++i) { assertEquals("Value not returned correctly", u32_values[i], lib.ret_u32(u32_values[i])); } } @Test public void returnS64() { returnS64(InvokerType.Default); } @Test public void returnFastLongS64() { returnS64(InvokerType.FastLong); } @Test public void returnFastNumericS64() { returnS64(InvokerType.FastNumeric); } @Test public void returnPointerArrayS64() { returnS64(InvokerType.PointerArray); } private void returnS64(InvokerType type) { LibNumberTest lib = UnitHelper.loadTestLibrary(LibNumberTest.class, type); for (int i = 0; i < s64_values.length; ++i) { assertEquals("Value not returned correctly", s64_values[i], lib.ret_s64(s64_values[i])); } } @Test public void returnU64() { returnU64(InvokerType.Default); } @Test public void returnFastLongU64() { returnU64(InvokerType.FastLong); } @Test public void returnFastNumericU64() { returnU64(InvokerType.FastNumeric); } @Test public void returnPointerArrayU64() { returnU64(InvokerType.PointerArray); } private void returnU64(InvokerType type) { LibNumberTest lib = UnitHelper.loadTestLibrary(LibNumberTest.class, type); for (int i = 0; i < u64_values.length; ++i) { assertEquals("Value not returned correctly", u64_values[i], lib.ret_u64(u64_values[i])); } } @Test public void returnDefaultF32() { returnF32(InvokerType.Default); } @Test public void returnFastIntF32() { returnF32(InvokerType.FastInt); } @Test public void returnFastNumericF32() { returnF32(InvokerType.FastNumeric); } @Test public void returnPointerArrayF32() { returnF32(InvokerType.PointerArray); } private void returnF32(InvokerType type) { LibNumberTest lib = UnitHelper.loadTestLibrary(LibNumberTest.class, type); float[] values = { 0f, 1.0f, -2.0f }; for (int i = 0; i < values.length; ++i) { assertEquals("Value not returned correctly", values[i], lib.ret_float(values[i]), 0.1f); } } @Test public void returnDefaultF64() { returnF64(InvokerType.Default); } @Test public void returnFastNumericF64() { returnF64(InvokerType.FastNumeric); } @Test public void returnPointerArrayF64() { returnF64(InvokerType.PointerArray); } private void returnF64(InvokerType type) { LibNumberTest lib = UnitHelper.loadTestLibrary(LibNumberTest.class, type); double[] values = { 0d, 1.0d, -2.0d }; for (int i = 0; i < values.length; ++i) { assertEquals("Value not returned correctly", values[i], lib.ret_double(values[i]), 0.1f); } } }jffi-1.0.2/test/com/kenai/jffi/TypeTest.java0000644000175000017500000000227211424636215020563 0ustar twernertwerner/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package com.kenai.jffi; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; /** * * @author wayne */ public class TypeTest { public TypeTest() { } @BeforeClass public static void setUpClass() throws Exception { } @AfterClass public static void tearDownClass() throws Exception { } @Before public void setUp() { } @After public void tearDown() { } // TODO add test methods here. // The methods must be annotated with annotation @Test. For example: // // @Test // public void hello() {} @Test public void lookupBuiltinType() throws Throwable { Foreign foreign = Foreign.getInstance(); long handle = foreign.lookupBuiltinType(Foreign.TYPE_SINT8); assertEquals("Incorrect type", Type.SINT8.type(), foreign.getTypeType(handle)); assertEquals("Incorrect size", 1, foreign.getTypeSize(handle)); assertEquals("Incorrect alignment", 1, foreign.getTypeAlign(handle)); } }jffi-1.0.2/test/com/kenai/jffi/ForeignTest.java0000644000175000017500000000652011424636215021233 0ustar twernertwerner package com.kenai.jffi; import java.lang.reflect.Method; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; /** * Test internals of the Foreign class */ public class ForeignTest { public ForeignTest() { } @BeforeClass public static void setUpClass() throws Exception { } @AfterClass public static void tearDownClass() throws Exception { } @Before public void setUp() { } @After public void tearDown() { } // TODO add test methods here. // The methods must be annotated with annotation @Test. For example: // // @Test // public void hello() {} @Test public void version() { final int VERSION = Foreign.VERSION_MAJOR << 16 | Foreign.VERSION_MINOR << 8 | Foreign.VERSION_MICRO; int version = Foreign.getInstance().getVersion(); assertEquals("Bad version", VERSION, version); } @Test public void pageSize() { long pageSize = Foreign.getInstance().pageSize(); assertNotSame("Invalid page size", 0, pageSize); } @Test public void mmap() { if (Platform.getPlatform().getOS() != Platform.OS.WINDOWS) { final int SIZE = 123; long addr = Foreign.getInstance().mmap(0, SIZE, Foreign.PROT_READ | Foreign.PROT_WRITE, Foreign.MAP_PRIVATE | Foreign.MAP_ANON, -1, 0); assertNotSame("Failed to allocate memory", -1L, addr); } } @Test public void munmap() { if (Platform.getPlatform().getOS() != Platform.OS.WINDOWS) { final int SIZE = 123; long addr = Foreign.getInstance().mmap(0, SIZE, Foreign.PROT_READ | Foreign.PROT_WRITE, Foreign.MAP_PRIVATE | Foreign.MAP_ANON, -1, 0); assertNotSame("Failed to allocate memory", -1, addr); assertTrue("Failed to free memory", Foreign.getInstance().munmap(addr, SIZE) == 0); } } @Test public void writeToAllocatedMemory() { if (Platform.getPlatform().getOS() != Platform.OS.WINDOWS) { final int SIZE = 257; final byte[] MAGIC = {'t', 'e', 's', 't'}; long addr = Foreign.getInstance().mmap(0, SIZE, Foreign.PROT_READ | Foreign.PROT_WRITE, Foreign.MAP_PRIVATE | Foreign.MAP_ANON, -1, 0); assertNotSame("Failed to allocate memory", -1, addr); MemoryIO.getInstance().putByteArray(addr, MAGIC, 0, MAGIC.length); byte[] tmp = new byte[MAGIC.length]; MemoryIO.getInstance().getByteArray(addr, tmp, 0, MAGIC.length); assertArrayEquals("Incorrect data read back", MAGIC, tmp); assertTrue("Failed to free memory", Foreign.getInstance().munmap(addr, SIZE) == 0); } } static class ClosureProxy { void invoke(Closure.Buffer buf) {} } // @Test public void freeClosure() throws Throwable { // Method m = ClosureProxy.class.getDeclaredMethod("invoke", new Class[] { Closure.Buffer.class}); // long cl = Foreign.getInstance().newClosure(new ClosureProxy(), m, Type.VOID.handle, new long[0], 0); // Foreign.getInstance().freeClosure(cl); // } // @Test public void newNativeMethod() throws Throwable { // Foreign.getInstance().newNativeMethod("test", "()V", 0); // } }jffi-1.0.2/test/com/kenai/jffi/LibraryTest.java0000644000175000017500000000165511424636215021252 0ustar twernertwernerpackage com.kenai.jffi; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; /** * * @author wayne */ public class LibraryTest { public LibraryTest() { } @BeforeClass public static void setUpClass() throws Exception { } @AfterClass public static void tearDownClass() throws Exception { } @Before public void setUp() { } @After public void tearDown() { } // TODO add test methods here. // The methods must be annotated with annotation @Test. For example: // // @Test // public void hello() {} @Test public void dlopen() { String libName = UnitHelper.getCLibraryName(); long handle = Foreign.getInstance().dlopen(libName, Library.LAZY | Library.GLOBAL); assertNotSame("Could not open libc.so", 0L, handle); } } jffi-1.0.2/.settings/0000755000175000017500000000000011424636215014310 5ustar twernertwernerjffi-1.0.2/.settings/org.maven.ide.eclipse.prefs0000644000175000017500000000042011424636215021424 0ustar twernertwerner#Wed Dec 30 15:17:24 CET 2009 activeProfiles= eclipse.preferences.version=1 fullBuildGoals=process-test-resources includeModules=false resolveWorkspaceProjects=false resourceFilterGoals=process-resources resources\:testResources skipCompilerPlugin=true version=1 jffi-1.0.2/.settings/org.eclipse.jdt.core.prefs0000644000175000017500000000042211424636215021270 0ustar twernertwerner#Wed Dec 30 13:18:41 CET 2009 eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 org.eclipse.jdt.core.compiler.compliance=1.5 org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning org.eclipse.jdt.core.compiler.source=1.5 jffi-1.0.2/pom.xml0000644000175000017500000001412211424636215013707 0ustar twernertwerner 4.0.0 org.jruby.extras jffi jar 1.0.2 jffi Java wrapper around libffi http://github.com/wmeissner/jffi GNU LGPLv3 http://www.gnu.org/licenses/lgpl-3.0.txt repo scm:git:git://github.com/wmeissner/jffi.git http://github.com/wmeissner/jffi codehaus-jruby-repository JRuby Central Repository dav:https://dav.codehaus.org/repository/jruby codehaus-jruby-snapshot-repository JRuby Central Development Repository dav:https://dav.codehaus.org/snapshots.repository/jruby maven2-repository.dev.java.net Java.net Repository for Maven http://download.java.net/maven/2/ codehaus Codehaus Repository true false http://repository.codehaus.org maven2-repository.dev.java.net Java.net Repository for Maven http://download.java.net/maven/2/ wmeissner Wayne Meissner wmeissner@gmail.com junit junit 4.5 test true true make linux-profile linux freebsd-profile freebsd gmake build build/classes build/test/classes src org.apache.maven.plugins maven-compiler-plugin 2.0.2 1.5 1.5 maven-antrun-plugin 1.1 build-native-library generate-sources ${project.build.directory}/java run org.jvnet.wagon-svn wagon-svn 1.8 org.apache.maven.wagon wagon-webdav build/report jffi-1.0.2/.classpath0000644000175000017500000000060511424636215014356 0ustar twernertwerner jffi-1.0.2/LICENSE0000644000175000017500000000114411424636215013377 0ustar twernertwerner This code is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 3 only, as published by the Free Software Foundation. This code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License version 3 for more details. You should have received a copy of the GNU Lesser General Public License version 3 along with this work. If not, see . jffi-1.0.2/COPYING.LESSER0000644000175000017500000001672711424636215014436 0ustar twernertwerner GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. jffi-1.0.2/build.xml0000644000175000017500000001154311424636215014217 0ustar twernertwerner Builds, tests, and runs the project jffi. jffi-1.0.2/lib/0000755000175000017500000000000011424636215013140 5ustar twernertwernerjffi-1.0.2/lib/junit_4/0000755000175000017500000000000011424636215014514 5ustar twernertwernerjffi-1.0.2/lib/nblibraries.properties0000644000175000017500000000061311424636215017552 0ustar twernertwernerlibs.junit.classpath=\ ${base}/junit/junit-3.8.2.jar libs.junit.javadoc=\ ${base}/junit/junit-3.8.2-api.zip libs.junit_4.classpath=\ ${base}/junit_4/junit-4.5.jar libs.junit_4.javadoc=\ ${base}/junit_4/junit-4.5-api.zip libs.junit_4.src=\ ${base}/junit_4/junit-4.5-src.jar libs.CopyLibs.classpath=\ ${base}/CopyLibs/org-netbeans-modules-java-j2seproject-copylibstask.jar jffi-1.0.2/lib/junit/0000755000175000017500000000000011424636215014271 5ustar twernertwernerjffi-1.0.2/lib/CopyLibs/0000755000175000017500000000000011424636215014664 5ustar twernertwernerjffi-1.0.2/archive/0000755000175000017500000000000011424636215014013 5ustar twernertwernerjffi-1.0.2/COPYING0000644000175000017500000010451311424636215013431 0ustar twernertwerner GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . jffi-1.0.2/libtest/0000755000175000017500000000000011424636215014040 5ustar twernertwernerjffi-1.0.2/libtest/PointerTest.c0000644000175000017500000000476511424636215016500 0ustar twernertwerner/* * Copyright (c) 2007 Wayne Meissner. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include typedef void* ptr; typedef void* pointer; #ifdef _WIN32 typedef char* caddr_t; #endif #define RET(T) T ptr_ret_##T(void* arg1, int offset) { \ T tmp; memcpy(&tmp, (caddr_t) arg1 + offset, sizeof(tmp)); return tmp; \ } #define SET(T) void ptr_set_##T(void* arg1, int offset, T value) { \ memcpy((caddr_t) arg1 + offset, &value, sizeof(value)); \ } #define TEST(T) SET(T) RET(T) TEST(int8_t); TEST(int16_t); TEST(int32_t); TEST(int64_t); TEST(float); TEST(double); TEST(pointer); void* ptr_return_array_element(void **ptrArray, int arrayIndex) { return ptrArray[arrayIndex]; } void ptr_set_array_element(void **ptrArray, int arrayIndex, void *value) { ptrArray[arrayIndex] = value; } void* ptr_malloc(int size) { return calloc(1, size); } void ptr_free(void* ptr) { free(ptr); } void* ptr_from_address(uintptr_t addr) { return (void *) addr; } jffi-1.0.2/libtest/NumberTest.c0000644000175000017500000001170011424636215016273 0ustar twernertwerner/* * Copyright (c) 2007 Wayne Meissner. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include typedef int8_t s8; typedef uint8_t u8; typedef int16_t s16; typedef uint16_t u16; typedef int32_t s32; typedef uint32_t u32; typedef int64_t s64; typedef uint64_t u64; typedef signed long sL; typedef unsigned long uL; typedef float f32; typedef double f64; #if !defined(__OpenBSD__) typedef unsigned long ulong; #endif #define ADD(T) T add_##T(T arg1, T arg2) { return arg1 + arg2; } #define SUB(T) T sub_##T(T arg1, T arg2) { return arg1 - arg2; } #define MUL(T) T mul_##T(T arg1, T arg2) { return arg1 * arg2; } #define DIV(T) T div_##T(T arg1, T arg2) { return arg1 / arg2; } #define RET(T) T ret_##T(T arg1) { return arg1; } #define SET(T) static T T##_;void set_##T(T arg1) { T##_ = arg1; } #define GET(T) T get_##T() { return T##_; } typedef char* ptr; #define TEST(T) ADD(T) SUB(T) MUL(T) DIV(T) RET(T) SET(T) GET(T) TEST(s8); TEST(u8); TEST(s16); TEST(u16); TEST(s32); TEST(u32); TEST(s64); TEST(u64); TEST(float); TEST(double); TEST(long); TEST(ulong); #define ADD2(R, T1, T2) R add_##T1##T2##_##R(T1 arg1, T2 arg2) { return arg1 + arg2; } #define SUB2(R, T1, T2) R sub_##T1##T2##_##R(T1 arg1, T2 arg2) { return arg1 - arg2; } #define MUL2(R, T1, T2) R mul_##T1##T2##_##R(T1 arg1, T2 arg2) { return arg1 * arg2; } #define DIV2(R, T1, T2) R div_##T1##T2##_##R(T1 arg1, T2 arg2) { return arg1 / arg2; } #define T2__(R, T1, T2) ADD2(R, T1, T2) SUB2(R, T1, T2) MUL2(R, T1, T2) DIV2(R, T1, T2) #define T2_(R, T1) \ T2__(R, T1, s8) T2__(R, T1, u8) \ T2__(R, T1, s16) T2__(R, T1, u16) \ T2__(R, T1, s32) T2__(R, T1, u32) \ T2__(R, T1, sL) T2__(R, T1, uL) \ T2__(R, T1, s64) T2__(R, T1, u64) \ #define TEST2(R) \ T2_(R, s8) T2_(R, u8) T2_(R, s16) T2_(R, u16) T2_(R, s32) T2_(R, u32) \ T2_(R, sL) T2_(R, uL) T2_(R, s64) T2_(R, u64) #ifdef notyet TEST2(s32) TEST2(u32) TEST2(s64) TEST2(u64) #endif #define ADD3(R, T1, T2, T3) R add_##T1##T2##T3##_##R(T1 arg1, T2 arg2, T3 arg3) { return arg1 + arg2 + arg3; } #define pack_f32(buf, v) do { *(float *)(buf) = v; } while(0) #define pack_f64(buf, v) do { *(double *)(buf) = v; } while(0) #define pack_int(buf, v) do { *(buf) = v; } while(0) #define pack_s8 pack_int #define pack_u8 pack_int #define pack_s16 pack_int #define pack_u16 pack_int #define pack_s32 pack_int #define pack_u32 pack_int #define pack_s64 pack_int #define pack_u64 pack_int #define pack_sL pack_int #define pack_uL pack_int #define PACK3(R, T1, T2, T3) void pack_##T1##T2##T3##_##R(T1 arg1, T2 arg2, T3 arg3, R* r) { \ pack_##T1(&r[0], arg1); \ pack_##T2(&r[1], arg2); \ pack_##T3(&r[2], arg3); \ } #define T3___(R, T1, T2, T3) PACK3(R, T1, T2, T3) /* SUB2(R, T1, T2) MUL2(R, T1, T2) DIV2(R, T1, T2) */ #define T3__(R, T1, T2) \ T3___(R, T1, T2, s8) T3___(R, T1, T2, u8) \ T3___(R, T1, T2, s16) T3___(R, T1, T2, u16) \ T3___(R, T1, T2, s32) T3___(R, T1, T2, u32) \ T3___(R, T1, T2, sL) T3___(R, T1, T2, uL) \ T3___(R, T1, T2, s64) T3___(R, T1, T2, u64) \ T3___(R, T1, T2, f32) T3___(R, T1, T2, f64) \ #define T3_(R, T1) \ T3__(R, T1, s8) T3__(R, T1, u8) \ T3__(R, T1, s16) T3__(R, T1, u16) \ T3__(R, T1, s32) T3__(R, T1, u32) \ T3__(R, T1, sL) T3__(R, T1, uL) \ T3__(R, T1, s64) T3__(R, T1, u64) \ T3__(R, T1, f32) T3__(R, T1, f64) \ #define TEST3(R) \ T3_(R, s8) T3_(R, u8) T3_(R, s16) T3_(R, u16) T3_(R, s32) T3_(R, u32) \ T3_(R, sL) T3_(R, uL) T3_(R, s64) T3_(R, u64) T3_(R, f32) T3_(R, f64) TEST3(s64) jffi-1.0.2/libtest/EnumTest.c0000644000175000017500000000417611424636215015760 0ustar twernertwerner/* * Copyright (c) 2007 Wayne Meissner. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ int test_untagged_enum(int val) { return val; } int test_untagged_typedef_enum(int val) { return val; } typedef enum {c1, c2, c3, c4} enum_type1; enum_type1 test_tagged_typedef_enum1(enum_type1 val) { return val; } typedef enum {c5 = 42, c6, c7, c8} enum_type2; enum_type2 test_tagged_typedef_enum2(enum_type2 val) { return val; } typedef enum {c9 = 42, c10, c11 = 4242, c12} enum_type3; enum_type3 test_tagged_typedef_enum3(enum_type3 val) { return val; } typedef enum {c13 = 42, c14 = 4242, c15 = 424242, c16 = 42424242} enum_type4; enum_type4 test_tagged_typedef_enum4(enum_type4 val) { return val; } jffi-1.0.2/libtest/BufferTest.c0000644000175000017500000000420711424636215016260 0ustar twernertwerner/* * Copyright (C) 2007 Wayne Meissner * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define MEMSET(buf, value, size) do { \ int i; for (i = 0; i < size; ++i) buf[i] = value; \ } while(0) #define MEMCPY(dst, src, size) do { \ int i; for (i = 0; i < size; ++i) dst[i] = src[i]; \ } while(0) #define FILL(JTYPE, CTYPE) \ void fill##JTYPE##Buffer(CTYPE* buf, CTYPE value, int size) { MEMSET(buf, value, size); } #define COPY(JTYPE, CTYPE) \ void copy##JTYPE##Buffer(CTYPE* dst, CTYPE* src, int size) { MEMCPY(dst, src, size); } #define FUNC(JTYPE, CTYPE) \ FILL(JTYPE, CTYPE); \ COPY(JTYPE, CTYPE) FUNC(Byte, char); FUNC(Short, short); FUNC(Int, int); FUNC(Long, long long); FUNC(Float, float); FUNC(Double, double); jffi-1.0.2/libtest/LastErrorTest.c0000644000175000017500000000337111424636215016765 0ustar twernertwerner/* * Copyright (c) 2008 Wayne Meissner. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #if defined(_WIN32) || defined(__WIN32__) # include #else # include #endif int setLastError(int error) { #if defined(_WIN32) || defined(__WIN32__) SetLastError(error); #else errno = error; #endif return -1; } jffi-1.0.2/libtest/StringTest.c0000644000175000017500000000344111424636215016314 0ustar twernertwerner/* * Copyright (c) 2007 Wayne Meissner. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include int string_equals(const char* s1, const char* s2) { return strcmp(s1, s2) == 0; } void string_set(char* s1, const char* s2) { strcpy(s1, s2); } void string_concat(char* dst, const char* src) { strcat(dst, src); } void string_dummy(char* dummy) { } jffi-1.0.2/libtest/ReferenceTest.c0000644000175000017500000000407711424636215016752 0ustar twernertwerner/* * Copyright (c) 2007 Wayne Meissner. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #define REF(T) void ref_##T(T arg, T* result) { *result = arg; } #define ADD(T) void ref_add_##T(T arg1, T arg2, T* result) { *result = arg1 + arg2; } #define SUB(T) void ref_sub_##T(T arg1, T arg2, T* result) { *result = arg1 - arg2; } #define MUL(T) void ref_mul_##T(T arg1, T arg2, T* result) { *result = arg1 * arg2; } #define DIV(T) void ref_div_##T(T arg1, T arg2, T* result) { *result = arg1 / arg2; } #define TEST(T) ADD(T) SUB(T) MUL(T) DIV(T) REF(T) TEST(int8_t); TEST(int16_t); TEST(int32_t); TEST(int64_t); TEST(float); TEST(double); jffi-1.0.2/libtest/VariadicTest.c0000644000175000017500000000233411424636215016570 0ustar twernertwerner #include #include #include #include #include typedef int8_t s8; typedef uint8_t u8; typedef int16_t s16; typedef uint16_t u16; typedef int32_t s32; typedef uint32_t u32; typedef int64_t s64; typedef uint64_t u64; typedef signed long sL; typedef unsigned long uL; typedef float F; typedef double D; void pack_varargs(s64* buf, const char* fmt, ...) { va_list ap; int c; double d; va_start(ap, fmt); while ((c = *fmt++)) { switch (c) { case 'c': case 's': case 'i': *buf++ = va_arg(ap, s32); break; case 'l': *buf++ = va_arg(ap, long); break; case 'j': *buf++ = va_arg(ap, s64); break; case 'f': case 'd': d = va_arg(ap, double); memcpy(buf++, &d, sizeof(d)); break; case 'C': case 'S': case 'I': *buf++ = va_arg(ap, u32); break; case 'L': *buf++ = va_arg(ap, unsigned long); break; } } va_end(ap); } jffi-1.0.2/libtest/Benchmark.c0000644000175000017500000000517711424636215016110 0ustar twernertwerner/* * Copyright (c) 2007 Wayne Meissner. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include void returnVoid() { } void returnVoidI(int arg) { } int returnInt() { return 0; } int returnIntI(int arg) { return arg; } typedef int8_t s8; typedef uint8_t u8; typedef int16_t s16; typedef uint16_t u16; typedef int32_t s32; typedef uint32_t u32; typedef int64_t s64; typedef uint64_t u64; typedef float f32; typedef double f64; typedef void v; typedef char* S; typedef void* P; #define B6(R, T1, T2, T3, T4, T5, T6) R bench_##T1##T2##T3##T4##T5##T6##_##R(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6) {} #define B5(R, T1, T2, T3, T4, T5) R bench_##T1##T2##T3##T4##T5##_##R(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) {} #define B4(R, T1, T2, T3, T4) R bench_##T1##T2##T3##T4##_##R(T1 a1, T2 a2, T3 a3, T4 a4) {} #define B3(R, T1, T2, T3) R bench_##T1##T2##T3##_##R(T1 a1, T2 a2, T3 a3) {} #define B2(R, T1, T2) R bench_##T1##T2##_##R(T1 a1, T2 a2) {} #define B1(R, T1) R bench_##T1##_##R(T1 a1) {} #define BrV(T) B1(v, T); B2(v, T, T); B3(v, T, T, T); B4(v, T, T, T, T); B5(v, T, T, T, T, T); B6(v, T, T, T, T, T, T); BrV(u32); BrV(s32); BrV(s64); BrV(u64); BrV(f32); BrV(f64); BrV(S); BrV(P); jffi-1.0.2/libtest/ClosureTest.c0000644000175000017500000001135411424636215016464 0ustar twernertwerner/* * Copyright (c) 2007 Wayne Meissner. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include void testClosureVrV(void (*closure)(void)) { (*closure)(); } char testClosureVrB(char (*closure)(void)) { return (*closure)(); } short testClosureVrS(short (*closure)(void)) { return (*closure)(); } int testClosureVrI(int (*closure)(void)) { return (*closure)(); } long long testClosureVrL(long long (*closure)(void)) { return (*closure)(); } float testClosureVrF(float (*closure)(void)) { return (*closure)(); } double testClosureVrD(double (*closure)(void)) { return (*closure)(); } void* testClosureVrP(void* (*closure)(void)) { return (*closure)(); } void testClosureBrV(void (*closure)(char), char a1) { (*closure)(a1); } void testClosureSrV(void (*closure)(short), short a1) { (*closure)(a1); } void testClosureIrV(void (*closure)(int), int a1) { (*closure)(a1); } void testClosureLrV(void (*closure)(long long), long long a1) { (*closure)(a1); } void testClosureFrV(void (*closure)(float), float a1) { (*closure)(a1); } void testClosureDrV(void (*closure)(double), double a1) { (*closure)(a1); } void testOptionalClosureBrV(void (*closure)(char), char a1) { if (closure) { (*closure)(a1); } } struct s8f32s32 { char s8; float f32; int s32; }; // Takes a struct argument void testClosureTrV(void (*closure)(struct s8f32s32 s), struct s8f32s32* s) { (*closure)(*s); } // Returns a struct value struct s8f32s32 testClosureVrT(struct s8f32s32 (*closure)()) { return (*closure)(); } typedef int (*returnTypeClosure_t)(int) ; typedef returnTypeClosure_t (*lookupClosure_t)(); int testReturnsClosure(lookupClosure_t lookup, int val) { returnTypeClosure_t func = lookup ? (*lookup)() : NULL; return func ? (*func)(val) : 0; } static int multiplyByTwo(int value) { return value * 2; } returnTypeClosure_t testReturnsFunctionPointer() { return multiplyByTwo; } typedef int (*argumentClosure_t)(int); typedef int (*withArgumentClosure_t)(argumentClosure_t, int); int testArgumentClosure(withArgumentClosure_t closure_with, argumentClosure_t closure_arg, int val) { return (*closure_with)(closure_arg, val); } // // These macros produce functions of the form: // testClosureBIrV(void (*closure)(char, int), char a1, int a2) {} // #define C2_(J1, J2, N1, N2) \ void testClosure##J1##J2##rV(void (*closure)(N1, N2), N1 a1, N2 a2) \ { \ (*closure)(a1, a2); \ } #define C2(J, N) \ C2_(B, J, char, N) \ C2_(S, J, short, N) \ C2_(I, J, int, N) \ C2_(L, J, long long, N) \ C2_(F, J, float, N) \ C2_(D, J, double, N) \ C2(B, char); C2(S, short); C2(I, int); C2(L, long long); C2(F, float); C2(D, double); #define C3_(J1, J2, J3, N1, N2, N3) \ void testClosure##J1##J2##J3##rV(void (*closure)(N1, N2, N3), N1 a1, N2 a2, N3 a3) \ { \ (*closure)(a1, a2, a3); \ } #define C3(J, N) \ C3_(B, J, B, char, N, char) \ C3_(S, J, S, short, N, short) \ C3_(I, J, I, int, N, int) \ C3_(L, J, L, long long, N, long long) \ C3_(F, J, F, float, N, float) \ C3_(D, J, D, double, N, double) \ C3(B, char); C3(S, short); C3(I, int); C3(L, long long); C3(F, float); C3(D, double); C3_(B, S, I, char, short, int); C3_(B, S, L, char, short, long long); C3_(L, S, B, long long, short, char); C3_(L, B, S, long long, char, short); jffi-1.0.2/libtest/GNUmakefile0000644000175000017500000000747411424636215016126 0ustar twernertwerner# -*- makefile -*- BUILD_OS := $(strip $(shell uname -s | tr '[:upper:]' '[:lower:]')) OS ?= $(BUILD_OS) # Default value of $OS on Windows is Windows_NT ifeq ($(OS), Windows_NT) # that's how we detect x64... ifneq ($(findstring 64, $(BUILD_OS)),) OS = win64 else OS = win32 endif endif CPU = $(shell uname -m | sed -e 's/i[345678]86/i386/') MODEL = 32 # Default to 32bit compiles PLATFORM = $(CPU)-$(OS) ifeq ($(OS), sunos) OS = solaris endif ifneq ($(findstring cygwin,$(BUILD_OS)),) # cygwin is always x32 for now OS = win32 endif SRC_DIR = libtest BUILD_DIR ?= build TEST_BUILD_DIR = $(BUILD_DIR)/libtest # Set defaults to unix (linux/solaris/bsd) PREFIX = lib LIBEXT = so LIBNAME = $(PREFIX)test.$(LIBEXT) export MACOSX_DEPLOYMENT_TARGET=10.4 CCACHE := $(strip $(realpath $(shell which ccache 2> /dev/null))) TEST_SRCS = $(wildcard $(SRC_DIR)/*.c) TEST_OBJS := $(patsubst $(SRC_DIR)/%.c, $(TEST_BUILD_DIR)/%.o, $(TEST_SRCS)) # # Compiler/linker flags from: # http://weblogs.java.net/blog/kellyohair/archive/2006/01/compilation_of_1.html JFLAGS = -fno-omit-frame-pointer -fno-strict-aliasing OFLAGS = -O2 $(JFLAGS) WFLAGS = -W -Werror -Wall -Wno-unused -Wno-parentheses PICFLAGS = -fPIC SOFLAGS = -shared -mimpure-text -Wl,-O1 LDFLAGS += $(SOFLAGS) IFLAGS = -I"$(BUILD_DIR)" CFLAGS = $(OFLAGS) $(WFLAGS) $(IFLAGS) $(PICFLAGS) -D_REENTRANT ifeq ($(OS), win64) override CPU = x86_64 JDK_INCLUDES=-I$(JNI_DIR)/win32/include -I$(JNI_DIR)/win32/include/win32 CC = gcc -m64 CXX = g++ PICFLAGS = LDFLAGS += -Wl,--add-stdcall-alias PICFLAGS = PREFIX = LIBEXT = dll endif ifeq ($(OS), win32) CC += -mno-cygwin -mwin32 LDFLAGS += -mno-cygwin -Wl,--add-stdcall-alias PREFIX = PICFLAGS = LIBEXT = dll endif ifeq ($(OS), darwin) ARCHFLAGS = -arch ppc ifneq ($(findstring $(CPU), i386 x86_64),) ARCHFLAGS += -arch i386 -arch x86_64 endif CC = gcc-4.0 MACSDK = /Developer/SDKs/MacOSX10.4u.sdk CFLAGS += $(ARCHFLAGS) -isysroot $(MACSDK) -DTARGET_RT_MAC_CFM=0 CFLAGS += -fno-common LDFLAGS = $(ARCHFLAGS) -dynamiclib -Wl,-syslibroot,$(MACSDK) -mmacosx-version-min=10.4 # link against the universal libraries on ppc machines LDFLAGS += -L$(MACSDK)/usr/lib LIBEXT = dylib FFI_CFLAGS += -isysroot $(MACSDK) PICFLAGS = SOFLAGS = endif ifeq ($(OS), linux) SOFLAGS += -Wl,-soname,$(LIBNAME) endif ifeq ($(OS), solaris) CC = gcc CFLAGS += -std=c99 LD = /usr/ccs/bin/ld SOFLAGS = -shared -static-libgcc endif ifeq ($(OS), aix) LIBEXT = a SOFLAGS = -shared -static-libgcc PICFLAGS += -pthread endif ifneq ($(findstring bsd, $(OS)),) SOFLAGS = -shared -static-libgcc CFLAGS += -pthread LDFLAGS += -pthread endif ifneq ($(findstring cygwin, $(OS)),) CFLAGS += -mno-cygwin -mwin32 LDFLAGS += -mno-cygwin -Wl,--add-stdcall-alias LIBEXT = dll PREFIX = PICFLAGS = endif ifneq ($(findstring mingw, $(OS)),) LIBEXT = dll PICFLAGS= endif ifeq ($(CPU), sparcv9) MODEL = 64 endif ifeq ($(CPU), amd64) MODEL = 64 endif ifeq ($(CPU), x86_64) MODEL = 64 endif ifeq ($(CPU), s390x) MODEL = 64 endif ifeq ($(CPU), ppc64) MODEL = 64 endif # On platforms (linux, solaris) that support both 32bit and 64bit, force building for one or the other ifneq ($(strip $(findstring $(OS), linux solaris)),) # Change the CC/LD instead of CFLAGS/LDFLAGS, incase other things in the flags # makes the libffi build choke CC += -m$(MODEL) LD += -m$(MODEL) endif LIBTEST = $(BUILD_DIR)/$(LIBNAME) all: $(LIBTEST) $(TEST_BUILD_DIR)/%.o : $(SRC_DIR)/%.c @mkdir -p $(@D) $(CCACHE) $(CC) $(CFLAGS) -c $< -o $@ $(LIBTEST): $(TEST_OBJS) $(CC) -o $@ $(LDFLAGS) $(TEST_OBJS) -lm clean:: # nothing to do - ant will delete the build dir debug:: @echo OS="$(OS)" @echo BUILD_OS="$(BUILD_OS)" @echo JAVA_HOME="$(JAVA_HOME)" @echo JDK_HOME="$(JDK_HOME)" @echo "SRCS=$(TEST_SRCS)" jffi-1.0.2/libtest/GlobalVariable.c0000644000175000017500000000126711424636215017060 0ustar twernertwerner#include #include typedef int8_t s8; typedef uint8_t u8; typedef int16_t s16; typedef uint16_t u16; typedef int32_t s32; typedef uint32_t u32; typedef int64_t s64; typedef uint64_t u64; typedef signed long sL; typedef unsigned long uL; typedef float f32; typedef double f64; #if !defined(__OpenBSD__) typedef unsigned long ulong; #endif typedef void* pointer; typedef void* P; #define GVAR(T) \ extern T gvar_##T; \ T gvar_##T = (T) -1; \ T gvar_##T##_get() { return gvar_##T; }; \ void gvar_##T##_set(T v) { gvar_##T = v; } GVAR(s8); GVAR(u8); GVAR(s16); GVAR(u16); GVAR(s32); GVAR(u32); GVAR(s64); GVAR(u64); GVAR(long); GVAR(ulong); GVAR(pointer); jffi-1.0.2/libtest/StructTest.c0000644000175000017500000001074711424636215016341 0ustar twernertwerner/* * Copyright (c) 2007 Wayne Meissner. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include typedef char s8; typedef short s16; typedef int s32; typedef long long s64; typedef float f32; typedef double f64; typedef struct bugged_struct { unsigned char visible; unsigned int x; unsigned int y; short rx; short ry; unsigned char order; unsigned char size; } bugged_struct_t; unsigned int bugged_struct_size() { return sizeof(bugged_struct_t); } struct test1 { char b; short s; int i; long long j; long l; float f; double d; char string[32]; }; struct struct_with_array { char c; int a[5]; }; struct nested { int i; }; struct container { char first; struct nested s; }; int struct_align_nested_struct(struct container* a) { return a->s.i; } void* struct_field_array(struct struct_with_array* s) { return &s->a; } struct container* struct_make_container_struct(int i) { static struct container cs; memset(&cs, 0, sizeof(cs)); cs.first = 1; cs.s.i = i; return &cs; } #define T(x, type) \ type struct_field_##type(struct test1* t) { return t->x; } \ struct type##_align { char first; type value; }; \ type struct_align_##type(struct type##_align* a) { return a->value; } T(b, s8); T(s, s16); T(i, s32); T(j, s64); T(f, f32); T(d, f64); T(l, long); void struct_set_string(struct test1* t, char* s) { strcpy(t->string, s); } struct test1* struct_make_struct(char b, short s, int i, long long ll, float f, double d) { static struct test1 t; memset(&t, 0, sizeof(t)); t.b = b; t.s = s; t.i = i; t.j = ll; t.f = f; t.d = d; return &t; } typedef int (*add_cb)(int a1, int a2); typedef int (*sub_cb)(int a1, int a2); struct test2 { add_cb add_callback; sub_cb sub_callback; }; int struct_call_add_cb(struct test2* t, int a1, int a2) { return t->add_callback(a1, a2); } int struct_call_sub_cb(struct test2* t, int a1, int a2) { return t->sub_callback(a1, a2); } struct struct_with_array* struct_make_struct_with_array(int a_0, int a_1, int a_2, int a_3, int a_4) { static struct struct_with_array s; memset(&s, 0, sizeof(s)); s.a[0] = a_0; s.a[1] = a_1; s.a[2] = a_2; s.a[3] = a_3; s.a[4] = a_4; return &s; } struct s8s32 { char s8; int s32; }; struct s8s32 struct_return_s8s32() { struct s8s32 s; s.s8 = 0x7f; s.s32 = 0x12345678; return s; } struct s8s32 struct_s8s32_set(char s8, int s32) { struct s8s32 s; s.s8 = s8; s.s32 = s32; return s; } int struct_s8s32_get_s8(struct s8s32 s) { return s.s8; } int struct_s8s32_get_s32(struct s8s32 s) { return s.s32; } // Pass a struct and an int arg, ensure the int arg is passed correctly int struct_s8s32_s32_ret_s32(struct s8s32 s, int s32) { return s32; } // Pass a struct and a long long arg, ensure the long long arg is passed correctly long long struct_s8s32_s64_ret_s64(struct s8s32 s, long long s64) { return s64; } jffi-1.0.2/version.xml0000644000175000017500000000156211424636215014605 0ustar twernertwerner package com.kenai.jffi; public final class Version { private Version() {} public static final int MAJOR = ${jffi.version.major}; public static final int MINOR = ${jffi.version.minor}; public static final int MICRO = ${jffi.version.micro}; } jffi-1.0.2/.gitignore0000644000175000017500000000017411424636215014364 0ustar twernertwerner*.orig$ *.rej$ *~ nbproject/private build build.eclipse dist lib/nblibraries-private.properties jni/libffi/doc/libffi.info$ jffi-1.0.2/custom-build.xml0000644000175000017500000002220411424636215015523 0ustar twernertwerner jffi-1.0.2/.hgignore0000644000175000017500000000023111424636215014171 0ustar twernertwerner\.orig$ \.orig\..*$ \.chg\..*$ \.rej$ \.conflict\~$ ^nbproject/private ^build/.*$ ^dist ^lib/nblibraries-private.properties ^jni/libffi/doc/libffi.info$ jffi-1.0.2/nbproject/0000755000175000017500000000000011424636215014360 5ustar twernertwernerjffi-1.0.2/nbproject/project.xml0000644000175000017500000000132611424636215016552 0ustar twernertwerner org.netbeans.modules.java.j2seproject jffi 1.6.5 ./lib/nblibraries.properties jffi-1.0.2/nbproject/project.properties0000644000175000017500000000425411424636215020151 0ustar twernertwernerapplication.title=jffi application.vendor=wayne build.classes.dir=${build.dir}/classes build.classes.excludes=**/*.java,**/*.form # This directory is removed when the project is cleaned: build.dir=build build.generated.dir=${build.dir}/generated build.generated.sources.dir=${build.dir}/generated-sources # Only compile against the classpath explicitly listed here: build.sysclasspath=ignore build.test.classes.dir=${build.dir}/test/classes build.test.results.dir=${build.dir}/test/results # Uncomment to specify the preferred debugger connection transport: #debug.transport=dt_socket debug.classpath=\ ${run.classpath} debug.test.classpath=\ ${run.test.classpath} # This directory is removed when the project is cleaned: dist.dir=dist dist.jar=${dist.dir}/jffi.jar dist.javadoc.dir=${dist.dir}/javadoc endorsed.classpath= excludes=**/libffi/* includes=** jar.compress=true javac.classpath= # Space-separated list of extra javac options javac.compilerargs=-Xlint:unchecked javac.deprecation=true javac.source=1.5 javac.target=1.5 javac.test.classpath=\ ${javac.classpath}:\ ${build.classes.dir}:\ ${libs.junit_4.classpath} javadoc.additionalparam= javadoc.author=false javadoc.encoding=${source.encoding} javadoc.noindex=false javadoc.nonavbar=false javadoc.notree=false javadoc.private=false javadoc.splitindex=true javadoc.use=true javadoc.version=false javadoc.windowtitle= jaxbwiz.endorsed.dirs="${netbeans.home}/../ide12/modules/ext/jaxb/api" jnlp.codebase.type=local jnlp.codebase.url=file:/home/wayne/src/jffi~core/dist/ jnlp.descriptor=application jnlp.enabled=false jnlp.offline-allowed=false jnlp.signed=false meta.inf.dir=${src.dir}/META-INF platform.active=default_platform run.classpath=\ ${javac.classpath}:\ ${build.classes.dir} # Space-separated list of JVM arguments used when running the project # (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value # or test-sys-prop.name=value to set system properties for unit tests): run.jvmargs=-Djava.library.path=build/jni -Djffi.boot.library.path=build/jni run.test.classpath=\ ${javac.test.classpath}:\ ${build.test.classes.dir} source.encoding=UTF-8 src.dir=src test.src.dir=test jffi-1.0.2/nbproject/genfiles.properties0000644000175000017500000000071111424636215020271 0ustar twernertwernerbuild.xml.data.CRC32=ec53da38 build.xml.script.CRC32=dbdf3541 build.xml.stylesheet.CRC32=958a1d3e # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. nbproject/build-impl.xml.data.CRC32=36ba03e6 nbproject/build-impl.xml.script.CRC32=c380691b nbproject/build-impl.xml.stylesheet.CRC32=576378a2@1.32.1.45 jffi-1.0.2/nbproject/build-impl.xml0000644000175000017500000012553211424636215017150 0ustar twernertwerner Must set src.dir Must set test.src.dir Must set build.dir Must set dist.dir Must set build.classes.dir Must set dist.javadoc.dir Must set build.test.classes.dir Must set build.test.results.dir Must set build.classes.excludes Must set dist.jar Must set javac.includes Must select some files in the IDE or set javac.includes To run this application from the command line without Ant, try: java -cp "${run.classpath.with.dist.jar}" ${main.class} To run this application from the command line without Ant, try: java -jar "${dist.jar.resolved}" Must select one file in the IDE or set run.class Must select one file in the IDE or set run.class Must select one file in the IDE or set debug.class Must select one file in the IDE or set debug.class Must set fix.includes Must select some files in the IDE or set javac.includes Some tests failed; see details above. Must select some files in the IDE or set test.includes Some tests failed; see details above. Must select one file in the IDE or set test.class Must select one file in the IDE or set applet.url Must select one file in the IDE or set applet.url jffi-1.0.2/src/0000755000175000017500000000000011424636215013161 5ustar twernertwernerjffi-1.0.2/src/com/0000755000175000017500000000000011424636215013737 5ustar twernertwernerjffi-1.0.2/src/com/kenai/0000755000175000017500000000000011424636215015026 5ustar twernertwernerjffi-1.0.2/src/com/kenai/jffi/0000755000175000017500000000000011424636215015744 5ustar twernertwernerjffi-1.0.2/src/com/kenai/jffi/CallInfo.java0000644000175000017500000000160611424636215020301 0ustar twernertwerner/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ package com.kenai.jffi; public interface CallInfo { int getParameterCount(); public Type getReturnType(); public Type getParameterType(int parameterIndex); int getRawParameterSize(); } jffi-1.0.2/src/com/kenai/jffi/CallingConvention.java0000644000175000017500000000167611424636215022235 0ustar twernertwerner/* * Copyright (C) 2008 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ package com.kenai.jffi; /** * Defines the function calling conventions. */ public enum CallingConvention { /** * The default C calling convention */ DEFAULT, /** * Windows stdcall calling convention */ STDCALL; } jffi-1.0.2/src/com/kenai/jffi/ObjectBuffer.java0000644000175000017500000002167511424636215021162 0ustar twernertwerner/* * Copyright (C) 2008, 2009 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ package com.kenai.jffi; /** * Holds objects the native code must handle - such as primitive arrays */ final class ObjectBuffer { /** Copy the array contents to native memory before calling the function */ public static final int IN = 0x1; /** After calling the function, reload the array contents from native memory */ public static final int OUT = 0x2; /** Append a NUL byte to the array contents after copying to native memory */ public static final int ZERO_TERMINATE = 0x4; /** Pin the array memory and pass the JVM memory pointer directly to the function */ public static final int PINNED = 0x8; /** For OUT arrays, clear the temporary native memory area */ public static final int CLEAR = 0x10; /* * WARNING: The following flags cannot be altered without recompiling the native code */ static final int INDEX_SHIFT = 16; static final int INDEX_MASK = 0x00ff0000; static final int TYPE_SHIFT = 24; static final int TYPE_MASK = 0xff << TYPE_SHIFT; static final int PRIM_MASK = 0x0f << TYPE_SHIFT; static final int FLAGS_SHIFT = 0; static final int FLAGS_MASK = 0xff; static final int ARRAY = 0x10 << TYPE_SHIFT; static final int BUFFER = 0x20 << TYPE_SHIFT; static final int JNI = 0x40 << TYPE_SHIFT; static final int BYTE = 0x1 << TYPE_SHIFT; static final int SHORT = 0x2 << TYPE_SHIFT; static final int INT = 0x3 << TYPE_SHIFT; static final int LONG = 0x4 << TYPE_SHIFT; static final int FLOAT = 0x5 << TYPE_SHIFT; static final int DOUBLE = 0x6 << TYPE_SHIFT; /* NOTE: The JNI types can overlap the primitive type, since they are mutually exclusive */ /** The JNIEnv address */ public static final int JNIENV = 0x1 << TYPE_SHIFT; /** The jobject handle */ public static final int JNIOBJECT = 0x2 << TYPE_SHIFT; /** The objects stored in this buffer */ private Object[] objects = new Object[1]; /** * The flags/offset/length descriptor array. * * Along with each object, a 3-tuple is stored in the descriptor array. * * The first element of the tuple stores a mask of the type, parameter index and array flags * The second element stores the offset within the array the data starts. * The third element stores the length of data. */ private int[] info = new int[objects.length * 3]; /** The index of the next descriptor storage slot */ private int infoIndex = 0; /** The index of the next object storage slot */ private int objectIndex = 0; /** * Gets the number of objects stored in this ObjectBuffer. * * @return the number of objects already stored. */ final int objectCount() { return objectIndex; } /** * Gets the object descriptor array. * * @return An array of integers describing the objects stored. */ final int[] info() { return info; } /** * Gets the array of stored objects. * * @return An array of objects stored in this buffer. */ final Object[] objects() { return objects; } /** Ensures that sufficient space is available to insert at least one more object */ private final void ensureSpace() { if (objects.length <= (objectIndex + 1)) { Object[] newObjects = new Object[objects.length << 1]; System.arraycopy(objects, 0, newObjects, 0, objectIndex); objects = newObjects; int[] newInfo = new int[objects.length * 3]; System.arraycopy(info, 0, newInfo, 0, objectIndex * 3); info = newInfo; } } /** * Encodes the native object flags for an array. * * @param flags The array flags (IN, OUT) for the object. * @param type The type of the object. * @param index The parameter index the object should be passed as. * @return A bitmask of flags. */ private static final int makeArrayFlags(int flags, int type, int index) { return (flags & FLAGS_MASK) | ((index << INDEX_SHIFT) & INDEX_MASK) | type; } /** * Encodes the native object flags for an NIO Buffer. * * @param index The parameter index of the buffer. * @return A bitmask of flags. */ private static final int makeBufferFlags(int index) { return ((index << INDEX_SHIFT) & INDEX_MASK) | BUFFER; } private static final int makeJNIFlags(int index, int type) { return ((index << INDEX_SHIFT) & INDEX_MASK) | JNI | type; } /** * Adds a java byte array as a pointer parameter. * * @param array The java array to use as the pointer parameter. * @param offset The offset from the start of the array. * @param length The length of the array to use. * @param flags The flags to use (IN, OUT, NULTERMINATE) */ public void putArray(int index, byte[] array, int offset, int length, int flags) { putObject(array, offset, length, makeArrayFlags(flags, BYTE | ARRAY, index)); } /** * Adds a java short array as a pointer parameter. * * @param array The java array to use as the pointer parameter. * @param offset The offset from the start of the array. * @param length The length of the array to use. * @param flags The flags to use (IN, OUT) */ public void putArray(int index, short[] array, int offset, int length, int flags) { putObject(array, offset, length, makeArrayFlags(flags, SHORT | ARRAY, index)); } /** * Adds a java int array as a pointer parameter. * * @param array The java array to use as the pointer parameter. * @param offset The offset from the start of the array. * @param length The length of the array to use. * @param flags The flags to use (IN, OUT) */ public void putArray(int index, int[] array, int offset, int length, int flags) { putObject(array, offset, length, makeArrayFlags(flags, INT | ARRAY, index)); } /** * Adds a java long array as a pointer parameter. * * @param array The java array to use as the pointer parameter. * @param offset The offset from the start of the array. * @param length The length of the array to use. * @param flags The flags to use (IN, OUT) */ public void putArray(int index, long[] array, int offset, int length, int flags) { putObject(array, offset, length, makeArrayFlags(flags, LONG | ARRAY, index)); } /** * Adds a java float array as a pointer parameter. * * @param array The java array to use as the pointer parameter. * @param offset The offset from the start of the array. * @param length The length of the array to use. * @param flags The flags to use (IN, OUT) */ public void putArray(int index, float[] array, int offset, int length, int flags) { putObject(array, offset, length, makeArrayFlags(flags, FLOAT | ARRAY, index)); } /** * Adds a java double array as a pointer parameter. * * @param array The java array to use as the pointer parameter. * @param offset The offset from the start of the array. * @param length The length of the array to use. * @param flags The flags to use (IN, OUT) */ public void putArray(int index, double[] array, int offset, int length, int flags) { putObject(array, offset, length, makeArrayFlags(flags, DOUBLE | ARRAY, index)); } /** * Adds a java direct buffer as a pointer parameter. * @param buffer The buffer to use as a pointer argument. * @param offset An offset to add to the buffer native address. * @param length The length of the buffer to use. */ public void putDirectBuffer(int index, java.nio.Buffer obj, int offset, int length) { putObject(obj, offset, length, makeBufferFlags(index)); } /** * Put the address of the current JNIEnv into this parameter position * * @param index The index of the parameter. */ public void putJNI(int index, int type) { putObject(null, 0, 0, makeJNIFlags(index, type)); } private void putObject(Object array, int offset, int length, int flags) { ensureSpace(); objects[objectIndex++] = array; info[infoIndex++] = flags; info[infoIndex++] = offset; info[infoIndex++] = length; } } jffi-1.0.2/src/com/kenai/jffi/ArrayFlags.java0000644000175000017500000000447711424636215020656 0ustar twernertwerner/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ package com.kenai.jffi; /** * Flags to use when adding an array as a pointer parameter */ public final class ArrayFlags { /* Stop ArrayFlags from being intantiated */ private ArrayFlags() {} /** Copy the array contents to native memory before calling the function */ public static final int IN = ObjectBuffer.IN; /** After calling the function, reload the array contents from native memory */ public static final int OUT = ObjectBuffer.OUT; /** Pin the array memory and pass the JVM memory pointer directly to the function */ public static final int PINNED = ObjectBuffer.PINNED; /** Append a NUL byte to the array contents after copying to native memory */ public static final int NULTERMINATE = ObjectBuffer.ZERO_TERMINATE; /** For OUT arrays, clear the native memory area before passing to the native function */ public static final int CLEAR = ObjectBuffer.CLEAR; /** * Tests if the flags indicate data should be copied from native memory. * * @param flags The array flags. Any combination of IN | OUT | PINNED | NULTERMINATE. * @return true If array data should be copied from native memory. */ public static final boolean isOut(int flags) { return (flags & (OUT | IN)) != IN; } /** * Tests if the flags indicate data should be copied to native memory. * * @param flags The array flags. Any combination of IN | OUT | PINNED | NULTERMINATE. * @return true If array data should be copied to native memory. */ public static final boolean isIn(int flags) { return (flags & (OUT | IN)) != OUT; } } jffi-1.0.2/src/com/kenai/jffi/CallContextCache.java0000644000175000017500000001213411424636215021754 0ustar twernertwerner/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ package com.kenai.jffi; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class CallContextCache { private final Map contextCache = new ConcurrentHashMap(); private final ReferenceQueue contextReferenceQueue = new ReferenceQueue(); /** Holder class to do lazy allocation of the ClosureManager instance */ private static final class SingletonHolder { static final CallContextCache INSTANCE = new CallContextCache(); } /** * Gets the global instance of the CallContextCache * * @return An instance of a CallContextCache */ public static final CallContextCache getInstance() { return SingletonHolder.INSTANCE; } /** Constructs a ClosureManager */ private CallContextCache() { } public final CallContext getCallContext(Type returnType, Type[] parameterTypes, CallingConvention convention) { Signature signature = new Signature(returnType, parameterTypes, convention); CallContextRef ref = contextCache.get(signature); CallContext ctx; if (ref != null && (ctx = ref.get()) != null) { return ctx; } // Cull any dead references while ((ref = (CallContextRef) contextReferenceQueue.poll()) != null) { contextCache.remove(ref.signature); } ctx = new CallContext(returnType, (Type[]) parameterTypes.clone(), convention); contextCache.put(signature, new CallContextRef(signature, ctx, contextReferenceQueue)); return ctx; } private static final class CallContextRef extends SoftReference { final Signature signature; public CallContextRef(Signature signature, CallContext ctx, ReferenceQueue queue) { super(ctx, queue); this.signature = signature; } } private static final class Signature { /** * Keep references to the return and parameter types so they do not get * garbage collected until the closure does. */ private final Type returnType; private final Type[] parameterTypes; private final CallingConvention convention; private int hashCode = 0; public Signature(Type returnType, Type[] parameterTypes, CallingConvention convention) { if (returnType == null || parameterTypes == null) { throw new NullPointerException("null return type or parameter types array"); } this.returnType = returnType; this.parameterTypes = parameterTypes; this.convention = convention; } @Override public boolean equals(Object obj) { if (obj == null || getClass() != obj.getClass()) { return false; } final Signature other = (Signature) obj; if (this.convention != other.convention) { return false; } if (this.returnType != other.returnType && !this.returnType.equals(other.returnType)) { return false; } if (this.parameterTypes.length == other.parameterTypes.length) { for (int i = 0; i < this.parameterTypes.length; ++i) { if (this.parameterTypes[i] != other.parameterTypes[i] && (this.parameterTypes[i] == null || !this.parameterTypes[i].equals(other.parameterTypes[i]))) { return false; } } // All param types are same, return type is same, convention is same, so this is the same signature return true; } return false; } private final int calculateHashCode() { int hash = 7; hash = 53 * hash + (this.returnType != null ? this.returnType.hashCode() : 0); int paramHash = 1; for (int i = 0; i < parameterTypes.length; ++i) { paramHash = 31 * paramHash + parameterTypes[i].hashCode(); } hash = 53 * hash + paramHash; hash = 53 * hash + this.convention.hashCode(); return hash; } @Override public int hashCode() { return hashCode != 0 ? hashCode : (hashCode = calculateHashCode()); } } } jffi-1.0.2/src/com/kenai/jffi/Aggregate.java0000644000175000017500000000432611424636215020502 0ustar twernertwerner/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ package com.kenai.jffi; public abstract class Aggregate extends Type { /** The FFI type of this type */ private final int type; /** The size in bytes of this type */ private final int size; /** The minimum alignment of this type */ private final int align; /** The address of this type's ffi_type structure */ private final long handle; private volatile boolean disposed = false; public Aggregate(long handle) { if (handle == 0L) { throw new NullPointerException("Invalid ffi_type handle"); } this.handle = handle; this.type = Foreign.getInstance().getTypeType(handle); this.size = Foreign.getInstance().getTypeSize(handle); this.align = Foreign.getInstance().getTypeAlign(handle); } final long handle() { return handle; } public final int type() { return type; } public final int size() { return size; } public final int alignment() { return align; } public synchronized final void dispose() { if (disposed) { throw new RuntimeException("native handle already freed"); } disposed = true; Foreign.getInstance().freeAggregate(handle); } @Override protected void finalize() throws Throwable { try { if (!disposed) { dispose(); } } catch (Throwable t) { t.printStackTrace(System.err); } finally { super.finalize(); } } } jffi-1.0.2/src/com/kenai/jffi/Invoker.java0000644000175000017500000005271311424636215020234 0ustar twernertwerner/* * Copyright (C) 2008, 2009 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ package com.kenai.jffi; /** * Provides native function invocation facilities. */ public abstract class Invoker { /** The size in bits of a native memory address */ private static final long ADDRESS_SIZE = Platform.getPlatform().addressSize(); private final Foreign foreign = Foreign.getInstance(); /** Lazy initialization singleton holder */ private static final class SingletonHolder { private static final Invoker INSTANCE = ADDRESS_SIZE == 64 ? LP64.INSTANCE : ILP32.INSTANCE; } /** * Gets the Invoker singleton. * * @return An instance of Invoker. */ public static final Invoker getInstance() { return SingletonHolder.INSTANCE; } /** Creates a new Invoker */ private Invoker() {} /** * Invokes a function with no arguments, and returns a 32 bit integer. * * @param function The Function to invoke. * @return A 32 bit integer value. */ public final int invokeVrI(Function function) { return foreign.invokeVrI(function.getContextAddress()); } /** * Invokes a function with no arguments, and returns a 32 bit float. * * @param function The Function to invoke. * @return A 32 bit float value. */ public final float invokeVrF(Function function) { return foreign.invokeVrF(function.getContextAddress()); } /** * Invokes a function with no arguments, and returns a 32 bit integer. * * This method does not save the errno value. * * @param function The Function to invoke. * @return A 32 bit integer value. */ public final int invokeNoErrnoVrI(Function function) { return foreign.invokeNoErrnoVrI(function.getContextAddress()); } /** * Invokes a function with one integer argument, and returns a 32 bit integer. * * @param function The Function to invoke. * @param arg1 A 32 bit integer argument. * @return A 32 bit integer value. */ public final int invokeIrI(Function function, int arg1) { return foreign.invokeIrI(function.getContextAddress(), arg1); } /** * Invokes a function with one integer argument, and returns a 32 bit integer. * * This method does not save the errno value. * * @param function The Function to invoke. * @param arg1 A 32 bit integer argument. * @return A 32 bit integer value. */ public final int invokeNoErrnoIrI(Function function, int arg1) { return foreign.invokeNoErrnoIrI(function.getContextAddress(), arg1); } /** * Invokes a function with one integer argument, and returns a 32 bit float. * * @param function The Function to invoke. * @param arg1 A 32 bit integer argument. * @return A 32 bit float value. */ public final float invokeIrF(Function function, int arg1) { return foreign.invokeIrF(function.getContextAddress(), arg1); } /** * Invokes a function with two integer arguments, and returns a 32 bit integer. * * @param function The Function to invoke. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @return A 32 bit integer value. */ public final int invokeIIrI(Function function, int arg1, int arg2) { return foreign.invokeIIrI(function.getContextAddress(), arg1, arg2); } /** * Invokes a function with two integer arguments, and returns a 32 bit integer. * * This method does not save the errno value. * * @param function The Function to invoke. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @return A 32 bit integer value. */ public final int invokeNoErrnoIIrI(Function function, int arg1, int arg2) { return foreign.invokeNoErrnoIIrI(function.getContextAddress(), arg1, arg2); } /** * Invokes a function with two integer arguments, and returns a 32 bit float. * * @param function The Function to invoke. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @return A 32 bit float value. */ public final float invokeIIrF(Function function, int arg1, int arg2) { return foreign.invokeIIrF(function.getContextAddress(), arg1, arg2); } /** * Invokes a function with three integer arguments, and returns a 32 bit integer. * * @param function The Function to invoke. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @param arg3 The third 32 bit integer argument. * @return A 32 bit integer value. */ public final int invokeIIIrI(Function function, int arg1, int arg2, int arg3) { return foreign.invokeIIIrI(function.getContextAddress(), arg1, arg2, arg3); } /** * Invokes a function with three integer arguments, and returns a 32 bit integer. * * This method does not save the errno value. * * @param function The Function to invoke. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @param arg3 The third 32 bit integer argument. * @return A 32 bit integer value. */ public final int invokeNoErrnoIIIrI(Function function, int arg1, int arg2, int arg3) { return foreign.invokeNoErrnoIIIrI(function.getContextAddress(), arg1, arg2, arg3); } /** * Invokes a function with three integer arguments, and returns a 32 bit float. * * @param function The Function to invoke. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @param arg3 The third 32 bit integer argument. * @return A 32 bit float value. */ public final float invokeIIIrF(Function function, int arg1, int arg2, int arg3) { return foreign.invokeIIIrF(function.getContextAddress(), arg1, arg2, arg3); } /** * Invokes a function with no arguments, and returns a 64 bit integer. * * @param function The Function to invoke. * @return A 64 bit integer value. */ public final long invokeVrL(Function function) { return foreign.invokeVrL(function.getContextAddress()); } /** * Invokes a function with one 64 bit integer argument, and returns a 64 bit integer. * * @param function The Function to invoke. * @param arg1 The 64 bit integer argument. * @return A 64 bit integer value. */ public final long invokeLrL(Function function, long arg1) { return foreign.invokeLrL(function.getContextAddress(), arg1); } /** * Invokes a function with two 64 bit integer arguments, and returns a 64 bit integer. * * @param function The Function to invoke. * @param arg1 The first 64 bit integer argument. * @param arg2 The second 64 bit integer argument. * @return A 64 bit integer value. */ public final long invokeLLrL(Function function, long arg1, long arg2) { return foreign.invokeLLrL(function.getContextAddress(), arg1, arg2); } /** * Invokes a function with three 64 bit integer arguments, and returns a 64 bit integer. * * @param function The Function to invoke. * @param arg1 The first 64 bit integer argument. * @param arg2 The second 64 bit integer argument. * @param arg3 The third 64 bit integer argument. * @return A 64 bit integer value. */ public final long invokeLLLrL(Function function, long arg1, long arg2, long arg3) { return foreign.invokeLLLrL(function.getContextAddress(), arg1, arg2, arg3); } /** * Invokes a function with four 64 bit integer arguments, and returns a 64 bit integer. * * @param function The Function to invoke. * @param arg1 The first 64 bit integer argument. * @param arg2 The second 64 bit integer argument. * @param arg3 The third 64 bit integer argument. * @param arg4 The fourth 64 bit integer argument. * @return A 64 bit integer value. */ public final long invokeLLLLrL(Function function, long arg1, long arg2, long arg3, long arg4, long arg5) { return foreign.invokeLLLLrL(function.getContextAddress(), arg1, arg2, arg3, arg4); } /** * Invokes a function with five 64 bit integer arguments, and returns a 64 bit integer. * * @param function The Function to invoke. * @param arg1 The first 64 bit integer argument. * @param arg2 The second 64 bit integer argument. * @param arg3 The third 64 bit integer argument. * @param arg4 The fourth 64 bit integer argument. * @param arg5 The fifth 64 bit integer argument. * @return A 64 bit integer value. */ public final long invokeLLLLLrL(Function function, long arg1, long arg2, long arg3, long arg4, long arg5) { return foreign.invokeLLLLLrL(function.getContextAddress(), arg1, arg2, arg3, arg4, arg5); } /** * Invokes a function with six 64 bit integer arguments, and returns a 64 bit integer. * * @param function The Function to invoke. * @param arg1 The first 64 bit integer argument. * @param arg2 The second 64 bit integer argument. * @param arg3 The third 64 bit integer argument. * @param arg4 The fourth 64 bit integer argument. * @param arg5 The fifth 64 bit integer argument. * @param arg6 The sixth 64 bit integer argument. * @return A 64 bit integer value. */ public final long invokeLLLLLLrL(Function function, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6) { return foreign.invokeLLLLLLrL(function.getContextAddress(), arg1, arg2, arg3, arg4, arg5, arg6); } /** * Invokes a function with no arguments, and returns a numeric value. * * @param function The Function to invoke. * @return A numeric value. */ public final long invokeVrN(Function function) { return foreign.invokeVrN(function.getContextAddress()); } /** * Invokes a function with one numberic argument, and returns a numeric value. * * @param function The Function to invoke. * @param arg1 The numeric argument. * @return A numeric value. */ public final long invokeNrN(Function function, long arg1) { return foreign.invokeNrN(function.getContextAddress(), arg1); } /** * Invokes a function with two numeric arguments, and returns a numeric value. * * @param function The Function to invoke. * @param arg1 The first numeric argument. * @param arg2 The second numeric argument. * @return A numeric value. */ public final long invokeNNrN(Function function, long arg1, long arg2) { return foreign.invokeNNrN(function.getContextAddress(), arg1, arg2); } /** * Invokes a function with three numeric arguments, and returns a numeric value. * * @param function The Function to invoke. * @param arg1 The first numeric argument. * @param arg2 The second numeric argument. * @param arg3 The third numeric argument. * @return A numeric value. */ public final long invokeNNNrN(Function function, long arg1, long arg2, long arg3) { return foreign.invokeNNNrN(function.getContextAddress(), arg1, arg2, arg3); } /** * Invokes a function with four numeric arguments, and returns a numeric value. * * @param function The Function to invoke. * @param arg1 The first numeric argument. * @param arg2 The second numeric argument. * @param arg3 The third numeric argument. * @param arg3 The fourth numeric argument. * @return A numeric value. */ public final long invokeNNNNrN(Function function, long arg1, long arg2, long arg3, long arg4) { return foreign.invokeNNNNrN(function.getContextAddress(), arg1, arg2, arg3, arg4); } /** * Invokes a function with five numeric arguments, and returns a numeric value. * * @param function The Function to invoke. * @param arg1 The first numeric argument. * @param arg2 The second numeric argument. * @param arg3 The third numeric argument. * @param arg4 The fourth numeric argument. * @param arg5 The fifth numeric argument. * @return A numeric value. */ public final long invokeNNNNNrN(Function function, long arg1, long arg2, long arg3, long arg4, long arg5) { return foreign.invokeNNNNNrN(function.getContextAddress(), arg1, arg2, arg3, arg4, arg5); } /** * Invokes a function with six numeric arguments, and returns a numeric value. * * @param function The Function to invoke. * @param arg1 The first numeric argument. * @param arg2 The second numeric argument. * @param arg3 The third numeric argument. * @param arg4 The fourth numeric argument. * @param arg5 The fifth numeric argument. * @param arg6 The sixth numeric argument. * @return A numeric value. */ public final long invokeNNNNNNrN(Function function, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6) { return foreign.invokeNNNNNNrN(function.getContextAddress(), arg1, arg2, arg3, arg4, arg5, arg6); } /** * Invokes a function and returns a native memory address. * * @param function The Function to invoke. * @param buffer A buffer containing the arguments to the function. * @return A native memory address. */ public abstract long invokeAddress(Function function, HeapInvocationBuffer buffer); /** * Invokes a function and returns a 32 bit integer value. * * @param function The Function to invoke. * @param buffer A buffer containing the arguments to the function. * @return A native memory address. */ public final int invokeInt(Function function, HeapInvocationBuffer buffer) { ObjectBuffer objectBuffer = buffer.objectBuffer(); return objectBuffer != null ? invokeArrayWithObjectsInt32(function, buffer, objectBuffer) : foreign.invokeArrayReturnInt(function.getContextAddress(), buffer.array()); } /** * Invokes a function and returns a 64 bit integer value. * * @param function The Function to invoke. * @param buffer A buffer containing the arguments to the function. * @return A native memory address. */ public final long invokeLong(Function function, HeapInvocationBuffer buffer) { ObjectBuffer objectBuffer = buffer.objectBuffer(); return objectBuffer != null ? foreign.invokeArrayWithObjectsInt64(function.getContextAddress(), buffer.array(), objectBuffer.objectCount(), objectBuffer.info(), objectBuffer.objects()) : foreign.invokeArrayReturnLong(function.getContextAddress(), buffer.array()); } /** * Invokes a function and returns a 32 bit floating point value. * * @param function The Function to invoke. * @param buffer A buffer containing the arguments to the function. * @return A native memory address. */ public final float invokeFloat(Function function, HeapInvocationBuffer buffer) { ObjectBuffer objectBuffer = buffer.objectBuffer(); return objectBuffer != null ? foreign.invokeArrayWithObjectsFloat(function.getContextAddress(), buffer.array(), objectBuffer.objectCount(), objectBuffer.info(), objectBuffer.objects()) : foreign.invokeArrayReturnFloat(function.getContextAddress(), buffer.array()); } /** * Invokes a function and returns a 64 bit floating point value. * * @param function The Function to invoke. * @param buffer A buffer containing the arguments to the function. * @return A native memory address. */ public final double invokeDouble(Function function, HeapInvocationBuffer buffer) { ObjectBuffer objectBuffer = buffer.objectBuffer(); return objectBuffer != null ? foreign.invokeArrayWithObjectsDouble(function.getContextAddress(), buffer.array(), objectBuffer.objectCount(), objectBuffer.info(), objectBuffer.objects()) : foreign.invokeArrayReturnDouble(function.getContextAddress(), buffer.array()); } /** * Invokes a function that returns a C struct by value. * * @param function The Function to invoke. * @param buffer The parameter buffer. * @return A byte array with the return value encoded in native byte order. */ public final byte[] invokeStruct(Function function, HeapInvocationBuffer buffer) { byte[] returnBuffer = new byte[function.getReturnType().size()]; invokeStruct(function, buffer, returnBuffer, 0); return returnBuffer; } /** * Invokes a function that returns a C struct by value. * * @param function The Function to invoke. * @param buffer The parameter buffer. * @param returnBuffer The output buffer to place the return value in. * @param offset The offset within returnBuffer to place the return value. */ public final void invokeStruct(Function function, HeapInvocationBuffer buffer, byte[] returnBuffer, int offset) { ObjectBuffer objectBuffer = buffer.objectBuffer(); if (objectBuffer != null) { foreign.invokeArrayWithObjectsReturnStruct(function.getContextAddress(), buffer.array(), objectBuffer.objectCount(), objectBuffer.info(), objectBuffer.objects(), returnBuffer, offset); } else { foreign.invokeArrayReturnStruct(function.getContextAddress(), buffer.array(), returnBuffer, offset); } } public final Object invokeObject(Function function, HeapInvocationBuffer buffer) { ObjectBuffer objectBuffer = buffer.objectBuffer(); return foreign.invokeArrayWithObjectsReturnObject(function.getContextAddress(), buffer.array(), objectBuffer.objectCount(), objectBuffer.info(), objectBuffer.objects()); } /** * Invokes a function, with the parameters loaded into native memory buffers, * and the function result is stored in a native memory buffer. * * @param function The Function to invoke. * @param returnBuffer The address of the native buffer to place the result * of the function call in. * @param parameters An array of addresses of the function parameters. */ public final void invoke(Function function, long returnBuffer, long[] parameters) { foreign.invokePointerParameterArray(function.getContextAddress(), returnBuffer, parameters); } /** * Convenience method to pass the objects and object descriptor array down as * normal arguments, so hotspot can optimize it. This is faster than the native * code pulling the objects and descriptors out of arrays. * * @param function The Function to invoke. * @param buffer A buffer containing the arguments to the function. * @param objectBuffer A buffer containing objects to be passed to the native function. * @return A 32 bit integer value. */ private final int invokeArrayWithObjectsInt32(Function function, HeapInvocationBuffer buffer, ObjectBuffer objectBuffer) { Object[] objects = objectBuffer.objects(); int[] info = objectBuffer.info(); int objectCount = objectBuffer.objectCount(); switch (objectCount) { case 1: return foreign.invokeArrayO1Int32(function.getContextAddress(), buffer.array(), objects[0], info[0], info[1], info[2]); case 2: return foreign.invokeArrayO2Int32(function.getContextAddress(), buffer.array(), objects[0], info[0], info[1], info[2], objects[1], info[3], info[4], info[5]); } return foreign.invokeArrayWithObjectsInt32(function.getContextAddress(), buffer.array(), objectCount, info, objects); } /** * A 32 bit invoker implementation */ private static final class ILP32 extends Invoker { private static final Invoker INSTANCE = new ILP32(); public final long invokeAddress(Function function, HeapInvocationBuffer buffer) { return (long) invokeInt(function, buffer); } } /** * A 64 bit invoker implementation */ private static final class LP64 extends Invoker { private static final Invoker INSTANCE = new LP64(); public long invokeAddress(Function function, HeapInvocationBuffer buffer) { return invokeLong(function, buffer); } } } jffi-1.0.2/src/com/kenai/jffi/ClosurePool.java0000644000175000017500000002250211424636215021056 0ustar twernertwerner/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ package com.kenai.jffi; import java.lang.ref.WeakReference; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; final class ClosurePool { private final List partial = new LinkedList(); private final List full = new LinkedList(); private final Set magazines = new HashSet(); // // Since the CallContext native handle is used by the native pool code // a strong reference to the call context needs to be kept. // private final CallContext callContext; ClosurePool(CallContext callContext) { this.callContext = callContext; } synchronized void recycle(Magazine magazine) { magazine.recycle(); if (!magazine.isEmpty()) { MagazineHolder h = new MagazineHolder(this, magazine); if (magazine.isFull()) { full.add(h); } else { partial.add(h); } } else { // If the magazine was empty during recycling, it means all the closures // allocated from it set autorelease=false, so we cannot re-use it. // Let GC clean it up. magazines.remove(magazine); } } private synchronized MagazineHolder getMagazineHolder() { if (!partial.isEmpty()) { return partial.get(0); } else if (!full.isEmpty()) { MagazineHolder h = full.remove(0); partial.add(h); return h; } Magazine m = new Magazine(callContext); MagazineHolder h = new MagazineHolder(this, m); partial.add(h); magazines.add(m); return h; } public synchronized Closure.Handle newClosureHandle(Closure closure) { Magazine.Slot s = null; MagazineHolder h = null; do { h = getMagazineHolder(); s = h.magazine.get(); if (s == null) { partial.remove(0); } } while (s == null); s.proxy.closure = closure; return new Handle(s, h); } /** * Manages the lifecycle of a native closure. * * Implements {@link Closure.Handle} interface. */ private static final class Handle implements Closure.Handle { /** * Keep references to the closure pool so it does not get garbage collected * until all closures using it do. */ private final MagazineHolder holder; private final Magazine.Slot slot; private volatile boolean disposed = false; /** * Creates a new Handle to lifecycle manager the native closure. * * @param handle The address of the native closure structure. * @param pool The native pool the closure was allocated from. */ Handle(Magazine.Slot slot, MagazineHolder holder) { this.slot = slot; this.holder = holder; } public long getAddress() { return slot.cbAddress; } public void setAutoRelease(boolean autorelease) { slot.autorelease = autorelease; } @Deprecated public void free() { dispose(); } public synchronized void dispose() { if (disposed) { throw new IllegalStateException("closure already disposed"); } disposed = true; slot.autorelease = true; } } private static final class Magazine { /** Store a reference to the MemoryIO accessor here for easy access */ private static final com.kenai.jffi.MemoryIO IO = com.kenai.jffi.MemoryIO.getInstance(); private final CallContext ctx; private final long magazine; private boolean nativeEmpty = false; private final List free = new ArrayList(); private final List all = new ArrayList(); Magazine(CallContext ctx) { this.ctx = ctx; this.magazine = Foreign.getInstance().newClosureMagazine(ctx.getAddress(), Proxy.METHOD); } Slot get() { if (!free.isEmpty()) { return free.remove(free.size() - 1); } return !nativeEmpty ? newSlot() : null; } private Slot newSlot() { Proxy proxy = new Proxy(ctx); long h = Foreign.getInstance().closureMagazineGet(magazine, proxy); if (h == 0) { nativeEmpty = true; return null; } Slot s = new Slot(h, proxy); all.add(s); return s; } boolean isFull() { return free.size() == all.size(); } boolean isEmpty() { return free.isEmpty(); } void recycle() { free.clear(); for (Slot s : all) { if (s.autorelease) { s.proxy.closure = NULL_CLOSURE; free.add(s); } } } @Override protected void finalize() throws Throwable { try { boolean release = true; // // If any of the closures allocated from this magazine set autorelease=false // then this magazine cannot be freed, so just let it leak // for (Slot s : all) { if (!s.autorelease) { release = false; break; } } if (magazine != 0 && release) { Foreign.getInstance().freeClosureMagazine(magazine); } } finally { super.finalize(); } } static final class Slot { /** * The address of the native closure structure. * * Note: This is NOT the code address, but a pointer to the structure * which contains the code address. */ final long handle; /** The code trampoline address */ final long cbAddress; final Proxy proxy; volatile boolean autorelease; public Slot(long handle, Proxy proxy) { this.handle = handle; this.proxy = proxy; this.autorelease = true; cbAddress = IO.getAddress(handle); } } } private static final class MagazineHolder { private final WeakReference poolref; private final Magazine magazine; public MagazineHolder(ClosurePool pool, Magazine magazine) { this.poolref = new WeakReference(pool); this.magazine = magazine; } @Override protected void finalize() throws Throwable { try { ClosurePool pool = poolref.get(); if (pool != null) { pool.recycle(magazine); } } finally { super.finalize(); } } } /** * This is a proxy passed to the native code, to be called by the * native trampoline code. */ static final class Proxy { static final Method METHOD = getMethod(); /** * Keep references to the return and parameter types so they do not get * garbage collected until the closure does. */ final CallContext callContext; volatile Closure closure; /** * Gets the * @return */ private static final Method getMethod() { try { return Proxy.class.getDeclaredMethod("invoke", new Class[]{long.class, long.class}); } catch (Throwable ex) { throw new RuntimeException(ex); } } Proxy(CallContext callContext) { this.closure = NULL_CLOSURE; this.callContext = callContext; } /** * Invoked by the native closure trampoline to execute the java side of * the closure. * * @param retvalAddress The address of the native return value buffer * @param paramAddress The address of the native parameter buffer. */ void invoke(long retvalAddress, long paramAddress) { closure.invoke(new DirectClosureBuffer(callContext, retvalAddress, paramAddress)); } } private static final Closure NULL_CLOSURE = new Closure() { public void invoke(Buffer buffer) { } }; } jffi-1.0.2/src/com/kenai/jffi/NativeType.java0000644000175000017500000000150211424636215020675 0ustar twernertwernerpackage com.kenai.jffi; /** * */ public enum NativeType { VOID(Foreign.TYPE_VOID), FLOAT(Foreign.TYPE_FLOAT), DOUBLE(Foreign.TYPE_DOUBLE), LONGDOUBLE(Foreign.TYPE_LONGDOUBLE), UINT8(Foreign.TYPE_UINT8), SINT8(Foreign.TYPE_SINT8), UINT16(Foreign.TYPE_UINT16), SINT16(Foreign.TYPE_SINT16), UINT32(Foreign.TYPE_UINT32), SINT32(Foreign.TYPE_SINT32), UINT64(Foreign.TYPE_UINT64), SINT64(Foreign.TYPE_SINT64), POINTER(Foreign.TYPE_POINTER), UCHAR(Foreign.TYPE_UCHAR), SCHAR(Foreign.TYPE_SCHAR), USHORT(Foreign.TYPE_USHORT), SSHORT(Foreign.TYPE_SSHORT), UINT(Foreign.TYPE_UINT), SINT(Foreign.TYPE_SINT), ULONG(Foreign.TYPE_ULONG), SLONG(Foreign.TYPE_SLONG); final int ffiType; NativeType(int ffiType) { this.ffiType = ffiType; } } jffi-1.0.2/src/com/kenai/jffi/CallContext.java0000644000175000017500000001323411424636215021032 0ustar twernertwerner/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ package com.kenai.jffi; /** * Native function call context * * This class holds all the information that JFFI needs to correctly call a * native function, or to implement a callback from native code to java. */ public final class CallContext implements CallInfo { /** The native address of the context */ private final long contextAddress; /** Whether the native context has been freed yet */ private volatile boolean disposed = false; /** The number of parameters this function takes */ private final int parameterCount; /** The size of buffer required when packing parameters */ private final int rawParameterSize; /** The return type of this function */ private final Type returnType; /** The parameter types of this function */ private final Type[] parameterTypes; /** * Creates a new instance of Function with default calling convention. * * @param address The native address of the function to invoke. * @param returnType The return type of the native function. * @param parameterTypes The parameter types the function accepts. */ public CallContext(Type returnType, Type... paramTypes) { this(returnType, paramTypes, CallingConvention.DEFAULT, true); } /** * Creates a new instance of Function. * * Function instances created with this constructor will save the * C errno contents after each call. * * @param address The native address of the function to invoke. * @param returnType The return type of the native function. * @param parameterTypes The parameter types the function accepts. * @param convention The calling convention of the function. */ public CallContext(Type returnType, Type[] paramTypes, CallingConvention convention) { this(returnType, paramTypes, convention, true); } /** * Creates a new instance of Function. * * @param address The native address of the function to invoke. * @param returnType The return type of the native function. * @param parameterTypes The parameter types the function accepts. * @param convention The calling convention of the function. * @param saveErrno Whether the errno should be saved or not */ public CallContext(Type returnType, Type[] paramTypes, CallingConvention convention, boolean saveErrno) { final int flags = (!saveErrno ? Foreign.F_NOERRNO : 0) | (convention == CallingConvention.STDCALL ? Foreign.F_STDCALL : Foreign.F_DEFAULT); final long h = Foreign.getInstance().newCallContext(returnType.handle(), Type.nativeHandles(paramTypes), flags); if (h == 0) { throw new RuntimeException("Failed to create native function"); } this.contextAddress = h; // // Keep references to the return and parameter types so they do not get // garbage collected // this.returnType = returnType; this.parameterTypes = (Type[]) paramTypes.clone(); this.parameterCount = paramTypes.length; this.rawParameterSize = Foreign.getInstance().getFunctionRawParameterSize(h); } /** * Gets the number of parameters the native function accepts. * * @return The number of parameters the native function accepts. */ public final int getParameterCount() { return parameterCount; } /** * Gets the number of bytes required to pack all the parameters this function * accepts, into a region of memory. * * @return The number of bytes required to store all paraameters of this function. */ public final int getRawParameterSize() { return rawParameterSize; } /** * Gets the address of the function context. * * @return The address of the native function context struct. */ final long getAddress() { return contextAddress; } /** * Gets the native return type of this function. * * @return The native return type of this function. */ public final Type getReturnType() { return returnType; } /** * Gets the type of a parameter. * * @param index The index of the parameter in the function signature * @return The Type of the parameter. */ public final Type getParameterType(int index) { return parameterTypes[index]; } public synchronized final void dispose() { if (disposed) { throw new RuntimeException("context already freed"); } Foreign.getInstance().freeCallContext(contextAddress); disposed = true; } @Override protected void finalize() throws Throwable { try { if (contextAddress != 0 && !disposed) { Foreign.getInstance().freeCallContext(contextAddress); } } catch (Throwable t) { t.printStackTrace(System.err); } finally { super.finalize(); } } } jffi-1.0.2/src/com/kenai/jffi/LastError.java0000644000175000017500000000376711424636215020541 0ustar twernertwerner/* * Copyright (C) 2008, 2009 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ package com.kenai.jffi; /** * Provides access to the value of errno on unix, or GetLastError on windows. */ public final class LastError { /** Lazy-initialization singleton holder */ private static final class SingletonHolder { static final LastError INSTANCE = new LastError(); } /** Creates a new LastError instance */ private LastError() {} /** * Gets the singleton instance of the LastError object. * * @return An instance of LastError */ public static final LastError getInstance() { return SingletonHolder.INSTANCE; } /** * Gets the errno set by the last C function invoked by the current thread. * * @return The value of errno/GetLastError() */ @Deprecated public final int getError() { return Foreign.getInstance().getLastError(); } /** * Gets the errno set by the last C function invoked by the current thread. * * @return The value of errno/GetLastError() */ public final int get() { return Foreign.getInstance().getLastError(); } /** * Sets the system errno value. * * @param value The value to set errno to. */ public final void set(int value) { Foreign.getInstance().setLastError(value); } } jffi-1.0.2/src/com/kenai/jffi/Foreign.java0000644000175000017500000014064411424636215020211 0ustar twernertwerner/* * Copyright (C) 2007, 2008, 2009 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ /** * Interface to the foreign function interface. */ package com.kenai.jffi; import java.lang.reflect.Method; import java.nio.Buffer; import java.nio.ByteBuffer; final class Foreign { private static abstract class InstanceHolder { static final InstanceHolder INSTANCE = getInstanceHolder(); private static final InstanceHolder getInstanceHolder() { try { Init.load(); Foreign foreign = new Foreign(); if ((foreign.getVersion() & 0xffff00) != (VERSION_MAJOR << 16 | VERSION_MINOR << 8)) { throw new UnsatisfiedLinkError("Incorrect native library version"); } foreign.init(); return new ValidInstanceHolder(foreign); } catch (UnsatisfiedLinkError ex) { return new InValidInstanceHolder(ex); } } abstract Foreign getForeign(); } private static final class ValidInstanceHolder extends InstanceHolder { final Foreign foreign; public ValidInstanceHolder(Foreign foreign) { this.foreign = foreign; } final Foreign getForeign() { return foreign; } } private static final class InValidInstanceHolder extends InstanceHolder { private final Error cause; public InValidInstanceHolder(Error cause) { this.cause = cause; } final Foreign getForeign() { throw cause; } } public static final Foreign getInstance() { return InstanceHolder.INSTANCE.getForeign(); } private Foreign() { } private final static int getVersionField(String name) { try { Class c = Class.forName(Foreign.class.getPackage().getName() + ".Version"); return (Integer) c.getField(name).get(c); } catch (Throwable t) { throw new RuntimeException(t); } } public final static int VERSION_MAJOR = getVersionField("MAJOR"); public final static int VERSION_MINOR = getVersionField("MINOR"); public final static int VERSION_MICRO = getVersionField("MICRO"); public final static int TYPE_VOID = 0; public final static int TYPE_FLOAT = 2; public final static int TYPE_DOUBLE = 3; public final static int TYPE_LONGDOUBLE = 4; public final static int TYPE_UINT8 = 5; public final static int TYPE_SINT8 = 6; public final static int TYPE_UINT16 = 7; public final static int TYPE_SINT16 = 8; public final static int TYPE_UINT32 = 9; public final static int TYPE_SINT32 = 10; public final static int TYPE_UINT64 = 11; public final static int TYPE_SINT64 = 12; public final static int TYPE_STRUCT = 13; public final static int TYPE_POINTER = 14; public final static int TYPE_UCHAR = 101; public final static int TYPE_SCHAR = 102; public final static int TYPE_USHORT = 103; public final static int TYPE_SSHORT = 104; public final static int TYPE_UINT = 105; public final static int TYPE_SINT = 106; public final static int TYPE_ULONG = 107; public final static int TYPE_SLONG = 108; /** Perform lazy binding. Only resolve symbols as needed */ public static final int RTLD_LAZY = 0x00001; /** Resolve all symbols when loading the library */ public static final int RTLD_NOW = 0x00002; /** Symbols in this library are not made availabl to other libraries */ public static final int RTLD_LOCAL = 0x00004; /** All symbols in the library are made available to other libraries */ public static final int RTLD_GLOBAL = 0x00008; /** Pages can be read */ public static final int PROT_READ = 0x1; /** Pages can be written */ public static final int PROT_WRITE = 0x2; /** Pages can be executed */ public static final int PROT_EXEC = 0x4; /** Pages cannot be accessed */ public static final int PROT_NONE = 0x0; /** Share changes */ public static final int MAP_SHARED = 0x1; public static final int MAP_PRIVATE = 0x2; /** Use the specified address */ public static final int MAP_FIXED = 0x10; public static final int MAP_NORESERVE = 0x40; public static final int MAP_ANON = 0x100; public static final int MAP_ALIGN = 0x200; /** Code segment memory */ public static final int MAP_TEXT = 0x400; /** Win32 VirtualAlloc/VirtualProtect flags */ public static final int PAGE_NOACCESS = 0x0001; public static final int PAGE_READONLY = 0x0002; public static final int PAGE_READWRITE = 0x0004; public static final int PAGE_WRITECOPY = 0x0008; public static final int PAGE_EXECUTE = 0x0010; public static final int PAGE_EXECUTE_READ = 0x0020; public static final int PAGE_EXECUTE_READWRITE = 0x0040; public static final int PAGE_EXECUTE_WRITECOPY = 0x0080; public static final int MEM_COMMIT = 0x1000; public static final int MEM_RESERVE = 0x2000; public static final int MEM_DECOMMIT = 0x4000; public static final int MEM_RELEASE = 0x8000; public static final int MEM_FREE = 0x10000; public static final int MEM_PRIVATE = 0x20000; public static final int MEM_MAPPED = 0x40000; public static final int MEM_RESET = 0x80000; public static final int MEM_TOP_DOWN = 0x100000; public static final int MEM_PHYSICAL = 0x400000; public static final int MEM_4MB_PAGES = 0x80000000; /* * possible return values for JNI functions. */ public static final int JNI_OK = 0; /* success */ public static final int JNI_ERR = (-1); /* unknown error */ public static final int JNI_EDETACHED = (-2); /* thread detached from the VM */ public static final int JNI_EVERSION = (-3); /* JNI version error */ public static final int JNI_ENOMEM = (-4); /* not enough memory */ public static final int JNI_EEXIST = (-5); /* VM already created */ public static final int JNI_EINVAL = (-6); /* invalid arguments */ /* * Function flags */ /** * Default calling convention */ public static final int F_DEFAULT = 0x0; /** * Windows STDCALL calling convention */ public static final int F_STDCALL = 0x1; /** * Do not save errno after each call */ public static final int F_NOERRNO = 0x2; /** * Gets the native stub library version. * * @return The version in the form of (VERSION_MAJOR << 16 | VERSION_MINOR << 8 | VERSION_MICRO) */ final native int getVersion(); /** * Initializes any native method/field/class ids */ private final native void init(); /** * Opens a dynamic library. * * This is a very thin wrapper around the native dlopen(3) call. * * @param name The name of the dynamic library to open. Pass null to get a * handle to the current process. * @param flags The flags to dlopen. A bitmask of {@link RTLD_LAZY}, {@link RTLD_NOW}, * {@link RTLD_LOCAL}, {@link RTLD_GLOBAL} * @return A native handle to the dynamic library. */ final native long dlopen(String name, int flags); /** * Closes a dynamic library opened by {@link dlopen}. * * @param handle The dynamic library handle returned by {@dlopen} */ final native void dlclose(long handle); /** * Locates the memory address of a dynamic library symbol. * * @param handle A dynamic library handle obtained from {@dlopen} * @param name The name of the symbol. * @return The address where the symbol in loaded in memory. */ final native long dlsym(long handle, String name); /** * Gets the last error raised by {@dlopen} or {@dlsym} * * @return The error string. */ final native String dlerror(); /** * Allocates native memory. * * @param size The number of bytes of memory to allocate * @param clear Whether the memory should be cleared (each byte set to zero). * @return The native address of the allocated memory. */ final native long allocateMemory(long size, boolean clear); /** * Releases memory allocated via {@link allocateMemory} back to the system. * * @param address The address of the memory to release. */ final native void freeMemory(long address); /** * Gets the size of a page of memory. * * @return The size of a memory page in bytes. */ final native long pageSize(); /** * Calls the Unix mmap(2) function * * This method is undefined on windows. * * @param addr The desired address to map the memory at, or 0 for random address. * @param len The length of the memory region. * @param prot The protection mode for the memory region. * @param flags * @param fd * @param off * @return The address of the mapping on success, -1 on error. */ final native long mmap(long addr, long len, int prot, int flags, int fd, long off); /** * Calls the Unix munmap(2) function. * * @param addr The address to unmap. * @param len The size of the region. * @return 0 on success, -1 on error. */ final native int munmap(long addr, long len); /** * Calls the Unix mprotect(2) function. * @param addr The address to unmap. * @param len The size of the region. * @param prot The new protection mode. * @return 0 on success, -1 on error. */ final native int mprotect(long addr, long len, int prot); final native long VirtualAlloc(long addr, int size, int flags, int prot); final native boolean VirtualFree(long addr, int size, int flags); final native boolean VirtualProtect(long addr, int size, int prot); /** * Creates a new native function context. * * @param address The address of the native function to call * @param returnType The return type of the function * @param paramTypes The types of the parameters * @param flags A bitmask of F_DEFAULT, F_STDCALL or F_NOERRNO * @return The native address of a new function context */ final native long newFunction(long address, long returnType, long[] paramTypes, int flags); /** * Frees a function context created by {@link #newFunction} * * @param handle The native function context to free */ final native void freeFunction(long functionContext); /** * Gets the address of the function in a function context. * * @param functionContext The function context * @return The address of the native function. */ final native long getFunctionAddress(long functionContext); /** * Gets the size required to pack parameters for the function in libffi raw format. * * @param functionContext The function context * @return The size in bytes required to pack parameters in raw format */ final native int getFunctionRawParameterSize(long functionContext); /** * Creates a new native call context. * * @param returnType The return type of the function * @param paramTypes The types of the parameters * @param flags A bitmask of F_DEFAULT, F_STDCALL or F_NOERRNO * * @return The native address of a new function context */ final native long newCallContext(long returnType, long[] paramTypes, int flags); /** * Frees a call context created by {@link #newCallContext} * * @param handle The native function context to free */ final native void freeCallContext(long callContext); /** * Gets the size required to pack parameters for the function in libffi raw format. * * @param functionContext The function context * @return The size in bytes required to pack parameters in raw format */ final native int getCallContextRawParameterSize(long callContext); final native boolean isRawParameterPackingEnabled(); /** * Gets the last error returned by a native function * * @return An integer. */ final native int getLastError(); /** * Sets the native errno value * * @param error The value to set errno to. */ final native void setLastError(int error); final native long newClosureMagazine(long contextAddress, Method closureMethod); final native void freeClosureMagazine(long closurePool); final native long closureMagazineGet(long closurePool, Object proxy); /** * Gets the address of the ffi_type structure for the builtin type * * @param type The FFI type enum value * @return The address of the ffi_type struct for this type, or null */ final native long lookupBuiltinType(int type); /** * Gets the native size of the type * * @param handle Address of the type structure * @return The native size of the type */ final native int getTypeSize(long handle); /** * Gets the minimum required alignment of the FFI type * * @param handle Address of the type structure * @return The minimum required alignment */ final native int getTypeAlign(long handle); /** * Gets the primitive type enum for the FFI type * * @param handle Address of the type structure * @return The builtin primitive type of the type structure */ final native int getTypeType(long handle); /** * Allocates a new FFI struct or union layout * * @param fields An array of ffi_type pointers desccribing the fields of the struct * @param isUnion If true, then fields are all positioned at offset=0, else * fiels are sequentially positioned. * @return The native address of the ffi_type structure for the new struct layout */ final native long newStruct(long[] fields, boolean isUnion); /** * Allocates a new FFI array type * * @param fields An array of ffi_type pointers desccribing the fields of the struct * @param isUnion If true, then fields are all positioned at offset=0, else * fiels are sequentially positioned. * @return The native address of the ffi_type structure for the new struct layout */ final native long newArray(long elementType, int length); /** * Frees a FFI struct or array handle allocated via {@link #newStruct} or {@link #newArray}. * * @param handle The FFI struct handle */ final native void freeAggregate(long handle); /** * Invokes a function with no arguments, and returns a 32 bit integer. * * @param function The address of the function context structure from {@link #newFunction}. * @return A 32 bit integer value. */ final native int invokeVrI(long functionContext); /** * Invokes a function with no arguments, and returns a 32 bit float. * * @param function The address of the function context structure from {@link #newFunction}. * @return A 32 bit float value. */ final native float invokeVrF(long functionContext); /** * Invokes a function with no arguments, and returns a 32 bit integer. * * This method does not save the errno value. * * @param function The address of the function context structure from {@link #newFunction}. * @return A 32 bit integer value. */ final native int invokeNoErrnoVrI(long functionContext); /** * Invokes a function with one integer argument, and returns a 32 bit integer. * * @param function The address of the function context structure from {@link #newFunction}. * @param arg1 The 32 bit integer argument. * @return A 32 bit integer value. */ final native int invokeIrI(long functionContext, int arg1); /** * Invokes a function with one integer argument, and returns a 32 bit integer. * * This method does not save the errno value. * * @param function The address of the function context structure from {@link #newFunction}. * @param arg1 The 32 bit integer argument. * @return A 32 bit integer value. */ final native int invokeNoErrnoIrI(long functionContext, int arg1); /** * Invokes a function with one integer argument, and returns a 32 bit float. * * @param function The address of the function context structure from {@link #newFunction}. * @param arg1 The 32 bit integer argument. * @return A 32 bit float value. */ final native float invokeIrF(long functionContext, int arg1); /** * Invokes a function with two integer arguments, and returns a 32 bit integer. * * @param function The address of the function context structure from {@link #newFunction}. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @return A 32 bit integer value. */ final native int invokeIIrI(long functionContext, int arg1, int arg2); /** * Invokes a function with two integer arguments, and returns a 32 bit float. * * @param function The address of the function context structure from {@link #newFunction}. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @return A 32 bit float value. */ final native float invokeIIrF(long functionContext, int arg1, int arg2); /** * Invokes a function with two integer arguments, and returns a 32 bit integer. * * This method does not save the errno value. * * @param function The address of the function context structure from {@link #newFunction}. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @return A 32 bit integer value. */ final native int invokeNoErrnoIIrI(long functionContext, int arg1, int arg2); /** * Invokes a function with three integer arguments, and returns a 32 bit integer. * * @param function The address of the function context structure from {@link #newFunction}. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @param arg3 The third 32 bit integer argument. * @return A 32 bit integer value. */ final native int invokeIIIrI(long functionContext, int arg1, int arg2, int arg3); /** * Invokes a function with four integer arguments, and returns a 32 bit integer. * * @param function The address of the function context structure from {@link #newFunction}. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @param arg3 The third 32 bit integer argument. * @param arg4 The third 32 bit integer argument. * @return A 32 bit integer value. */ final native int invokeIIIIrI(long functionContext, int arg1, int arg2, int arg3, int arg4); /** * Invokes a function with five integer arguments, and returns a 32 bit integer. * * @param function The address of the function context structure from {@link #newFunction}. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @param arg3 The third 32 bit integer argument. * @param arg4 The fourth 32 bit integer argument. * @param arg5 The fifth 32 bit integer argument. * @return A 32 bit integer value. */ final native int invokeIIIIIrI(long functionContext, int arg1, int arg2, int arg3, int arg4, int arg5); /** * Invokes a function with six integer arguments, and returns a 32 bit integer. * * @param function The address of the function context structure from {@link #newFunction}. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @param arg3 The third 32 bit integer argument. * @param arg4 The fourth 32 bit integer argument. * @param arg5 The fifth 32 bit integer argument. * @param arg6 The sixth 32 bit integer argument. * @return A 32 bit integer value. */ final native int invokeIIIIIIrI(long functionContext, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6); /** * Invokes a function with three integer arguments, and returns a 32 bit float. * * @param function The address of the function context structure from {@link #newFunction}. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @param arg3 The third 32 bit integer argument. * @return A 32 bit float value. */ final native float invokeIIIrF(long functionContext, int arg1, int arg2, int arg3); /** * Invokes a function with three integer arguments, and returns a 32 bit integer. * * This method does not save the errno value. * * @param function The address of the function context structure from {@link #newFunction}. * @param arg1 The first 32 bit integer argument. * @param arg2 The second 32 bit integer argument. * @param arg3 The third 32 bit integer argument. * @return A 32 bit integer value. */ final native int invokeNoErrnoIIIrI(long functionContext, int arg1, int arg2, int arg3); /** * Invokes a function with no arguments, and returns a 64 bit integer. * * @param function The address of the function context structure from {@link #newFunction}. * @return A 64 bit integer value. */ final native long invokeVrL(long function); /** * Invokes a function with no arguments, and returns a 64 bit float. * * @param function The address of the function context structure from {@link #newFunction}. * @return A 64 bit float value. */ final native double invokeVrD(long function); /** * Invokes a function with one 64 bit integer argument, and returns a 64 bit integer. * * @param function The address of the function context structure from {@link #newFunction}. * @param arg1 The 64 bit integer argument. * @return A 64 bit integer value. */ final native long invokeLrL(long function, long arg1); /** * Invokes a function with one 64 bit integer argument, and returns a 64 bit float. * * @param function The address of the function context structure from {@link #newFunction}. * @param arg1 The 64 bit integer argument. * @return A 64 bit float value. */ final native double invokeLrD(long function, long arg1); /** * Invokes a function with two 64 bit integer arguments, and returns a 64 bit integer. * * @param function The address of the function context structure from {@link #newFunction}. * @param arg1 The first 64 bit integer argument. * @param arg2 The second 64 bit integer argument. * @return A 64 bit integer value. */ final native long invokeLLrL(long function, long arg1, long arg2); /** * Invokes a function with two 64 bit integer arguments, and returns a 64 bit float. * * @param function The address of the function context structure from {@link #newFunction}. * @param arg1 The first 64 bit integer argument. * @param arg2 The second 64 bit integer argument. * @return A 64 bit float value. */ final native double invokeLLrD(long function, long arg1, long arg2); /** * Invokes a function with three 64 bit integer arguments, and returns a 64 bit integer. * * @param function The address of the function context structure from {@link #newFunction}. * @param arg1 The first 64 bit integer argument. * @param arg2 The second 64 bit integer argument. * @param arg3 The third 64 bit integer argument. * @return A 64 bit integer value. */ final native long invokeLLLrL(long function, long arg1, long arg2, long arg3); /** * Invokes a function with four 64 bit integer arguments, and returns a 64 bit integer. * * @param function The address of the function context structure from {@link #newFunction}. * @param arg1 The first 64 bit integer argument. * @param arg2 The second 64 bit integer argument. * @param arg3 The third 64 bit integer argument. * @param arg4 The fourth 64 bit integer argument. * @return A 64 bit integer value. */ final native long invokeLLLLrL(long function, long arg1, long arg2, long arg3, long arg4); /** * Invokes a function with five 64 bit integer arguments, and returns a 64 bit integer. * * @param function The address of the function context structure from {@link #newFunction}. * @param arg1 The first 64 bit integer argument. * @param arg2 The second 64 bit integer argument. * @param arg3 The third 64 bit integer argument. * @param arg4 The fourth 64 bit integer argument. * @param arg5 The fifth 64 bit integer argument. * @return A 64 bit integer value. */ final native long invokeLLLLLrL(long function, long arg1, long arg2, long arg3, long arg4, long arg5); /** * Invokes a function with six 64 bit integer arguments, and returns a 64 bit integer. * * @param function The address of the function context structure from {@link #newFunction}. * @param arg1 The first 64 bit integer argument. * @param arg2 The second 64 bit integer argument. * @param arg3 The third 64 bit integer argument. * @param arg4 The fourth 64 bit integer argument. * @param arg5 The fifth 64 bit integer argument. * @param arg6 The sixth 64 bit integer argument. * @return A 64 bit integer value. */ final native long invokeLLLLLLrL(long function, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6); /** * Invokes a function with three 64 bit integer arguments, and returns a 64 bit float. * * @param function The address of the function context structure from {@link #newFunction}. * @param arg1 The first 64 bit integer argument. * @param arg2 The second 64 bit integer argument. * @param arg3 The third 64 bit integer argument. * @return A 64 bit float value. */ final native double invokeLLLrD(long function, long arg1, long arg2, long arg3); /** * Invokes a function with zero numeric arguments, and returns a numeric value. * * @param function The address of the function context structure from {@link #newFunction}. * @return A numeric value. */ final native long invokeVrN(long function); /** * Invokes a function with one numeric arguments, and returns a numeric value. * * @param function The address of the function context structure from {@link #newFunction}. * @param arg1 The first numeric argument. * @return A numeric value. */ final native long invokeNrN(long function, long arg1); /** * Invokes a function with two numeric arguments, and returns a numeric value. * * @param function The address of the function context structure from {@link #newFunction}. * @param arg1 The first numeric argument. * @param arg2 The second numeric argument. * @return A numeric value. */ final native long invokeNNrN(long function, long arg1, long arg2); /** * Invokes a function with three numeric arguments, and returns a numeric value. * * @param function The address of the function context structure from {@link #newFunction}. * @param arg1 The first numeric argument. * @param arg2 The second numeric argument. * @param arg3 The third numeric argument. * @return A numeric value. */ final native long invokeNNNrN(long function, long arg1, long arg2, long arg3); /** * Invokes a function with four numeric arguments, and returns a numeric value. * * @param function The address of the function context structure from {@link #newFunction}. * @param arg1 The first numeric argument. * @param arg2 The second numeric argument. * @param arg3 The third numeric argument. * @param arg4 The fourth numeric argument. * @return A numeric value. */ final native long invokeNNNNrN(long function, long arg1, long arg2, long arg3, long arg4); /** * Invokes a function with five numeric arguments, and returns a numeric value. * * @param function The address of the function context structure from {@link #newFunction}. * @param arg1 The first numeric argument. * @param arg2 The second numeric argument. * @param arg3 The third numeric argument. * @param arg4 The fourth numeric argument. * @param arg5 The fifth numeric argument. * @return A numeric value. */ final native long invokeNNNNNrN(long function, long arg1, long arg2, long arg3, long arg4, long arg5); /** * Invokes a function with six numeric arguments, and returns a numeric value. * * @param function The address of the function context structure from {@link #newFunction}. * @param arg1 The first numeric argument. * @param arg2 The second numeric argument. * @param arg3 The third numeric argument. * @param arg4 The fourth numeric argument. * @param arg5 The fifth numeric argument. * @param arg6 The sixth numeric argument. * @return A numeric value. */ final native long invokeNNNNNNrN(long function, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6); /** * Invokes a function that returns a 32 bit integer. * @param function The address of the function context structure from {@link #newFunction}. * @param buffer A byte array containing the aguments to the function. * @return A 32 bit integer value. */ final native int invokeArrayReturnInt(long function, byte[] buffer); /** * Invokes a function that returns a 64 bit integer. * @param function The address of the function context structure from {@link #newFunction}. * @param buffer A byte array containing the aguments to the function. * @return A 64 bit integer value. */ final native long invokeArrayReturnLong(long function, byte[] buffer); /** * Invokes a function that returns a 32 bit floating point value. * @param function The address of the function context structure from {@link #newFunction}. * @param buffer A byte array containing the aguments to the function. * @return A 32 bit floating point value. */ final native float invokeArrayReturnFloat(long function, byte[] buffer); /** * Invokes a function that returns a 64 bit floating point value. * @param function The address of the function context structure from {@link #newFunction}. * @param buffer A byte array containing the aguments to the function. * @return A 64 bit floating point value. */ final native double invokeArrayReturnDouble(long function, byte[] buffer); /** * Invokes a function and pack the return value into a byte array. * @param function The address of the function context structure from {@link #newFunction}. * @param buffer A byte array containing the aguments to the function. */ final native void invokeArrayReturnStruct(long function, byte[] paramBuffer, byte[] returnBuffer, int offset); /** * Invokes a function that returns a java object. * * This is only useful when calling JNI functions directly. * * @param function The address of the function context structure from {@link #newFunction}. * @param buffer A byte array containing the aguments to the function. */ final native Object invokeArrayWithObjectsReturnObject(long function, byte[] paramBuffer, int objectCount, int[] objectInfo, Object[] objects); /* ---------------------------------------------------------------------- */ final native int invokeArrayWithObjectsInt32(long function, byte[] buffer, int objectCount, int[] objectInfo, Object[] objects); final native long invokeArrayWithObjectsInt64(long function, byte[] buffer, int objectCount, int[] objectInfo, Object[] objects); final native float invokeArrayWithObjectsFloat(long function, byte[] buffer, int objectCount, int[] objectInfo, Object[] objects); final native double invokeArrayWithObjectsDouble(long function, byte[] buffer, int objectCount, int[] objectInfo, Object[] objects); final native void invokeArrayWithObjectsReturnStruct(long function, byte[] buffer, int objectCount, int[] objectInfo, Object[] objects, byte[] returnBuffer, int returnBufferOffset); /* ---------------------------------------------------------------------- */ final native int invokeArrayO1Int32(long function, byte[] buffer, Object o1, int o1Info, int o1off, int o1len); final native int invokeArrayO2Int32(long function, byte[] buffer, Object o1, int o1Info, int o1off, int o1len, Object o2, int o2info, int o2off, int o2len); final native long invokeArrayO1Int64(long function, byte[] buffer, Object o1, int o1Info, int o1off, int o1len); final native long invokeArrayO2Int64(long function, byte[] buffer, Object o1, int o1Info, int o1off, int o1len, Object o2, int o2info, int o2off, int o2len); /* ---------------------------------------------------------------------- */ /** * Invokes a function, with the parameters loaded into native memory buffers, * and the function result is stored in a native memory buffer. * * @param functionContext The address of the function context structure from {@link #newFunction}. * @param returnBuffer The address of the native buffer to place the result * of the function call in. * @param parameters An array of addresses of the function parameters. */ final native void invokePointerParameterArray(long functionContext, long returnBuffer, long[] parameters); /** * Reads an 8 bit integer from a native memory location. * * @param address The memory location to get the value from. * @return A byte containing the value. */ final native byte getByte(long address); /** * Reads a 16 bit integer from a native memory location. * * @param address The memory location to get the value from. * @return A short containing the value. */ final native short getShort(long address); /** * Reads a 32 bit integer from a native memory location. * * @param address The memory location to get the value from. * @return An int containing the value. */ final native int getInt(long address); /** * Reads a 64 bit integer from a native memory location. * * @param address The memory location to get the value from. * @return A long containing the value. */ final native long getLong(long address); /** * Reads a 32 bit floating point value from a native memory location. * * @param address The memory location to get the value from. * @return A float containing the value. */ final native float getFloat(long address); /** * Reads a 64 bit floating point value from a native memory location. * * @param address The memory location to get the value from. * @return A double containing the value. */ final native double getDouble(long address); /** * Reads a native memory address from a native memory location. * * @param address The memory location to get the value from. * @return A long containing the value. */ final native long getAddress(long address); /** * Writes an 8 bit integer value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ final native void putByte(long address, byte value); /** * Writes a 16 bit integer value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ final native void putShort(long address, short value); /** * Writes a 32 bit integer value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ final native void putInt(long address, int value); /** * Writes a 64 bit integer value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ final native void putLong(long address, long value); /** * Writes a 32 bit floating point value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ final native void putFloat(long address, float value); /** * Writes a 64 bit floating point value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ final native void putDouble(long address, double value); /** * Writes a native memory address value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ final native void putAddress(long address, long value); /** * Sets a region of native memory to a specific byte value. * * @param address The address of start of the native memory. * @param size The number of bytes to set. * @param value The value to set the native memory to. */ final native void setMemory(long address, long size, byte value); /** * Copies contents of a native memory location to another native memory location. * * @param src The source memory address. * @param dst The destination memory address. * @param size The number of bytes to copy. */ final native void copyMemory(long src, long dst, long size); /** * Writes a java byte array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ final native void putByteArray(long address, byte[] data, int offset, int length); /** * Reads a java byte array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ final native void getByteArray(long address, byte[] data, int offset, int length); /** * Writes a java char array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ final native void putCharArray(long address, char[] data, int offset, int length); /** * Reads a java char array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ final native void getCharArray(long address, char[] data, int offset, int length); /** * Writes a java short array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ final native void putShortArray(long address, short[] data, int offset, int length); /** * Reads a java short array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ final native void getShortArray(long address, short[] data, int offset, int length); /** * Writes a java int array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ final native void putIntArray(long address, int[] data, int offset, int length); /** * Reads a java int array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ final native void getIntArray(long address, int[] data, int offset, int length); /** * Writes a java long array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ final native void putLongArray(long address, long[] data, int offset, int length); /** * Reads a java long array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ final native void getLongArray(long address, long[] data, int offset, int length); /** * Writes a java double array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ final native void putFloatArray(long address, float[] data, int offset, int length); /** * Reads a java float array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ final native void getFloatArray(long address, float[] data, int offset, int length); /** * Writes a java double array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ final native void putDoubleArray(long address, double[] data, int offset, int length); /** * Reads a java double array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ final native void getDoubleArray(long address, double[] data, int offset, int length); /** * Gets the address of a byte value in a native memory region. * * @param address The native memory address to start searching. * @param value The value to search for. * @param len The size of the native memory region being searched. * @return The address of the value, or 0 (zero) if not found. */ final native long memchr(long address, int value, long len); /** * Copies potentially overlapping memory areas. * * @param dst The destination memory address. * @param src The source memory address. * @param size The number of bytes to copy. */ final native void memmove(long dst, long src, long len); /** * Copies non-overlapping memory areas. * * @param dst The destination memory address. * @param src The source memory address. * @param size The number of bytes to copy. */ final native void memcpy(long dst, long src, long len); /** * Gets the length of a native ascii or utf-8 string. * * @param address The native address of the string. * @return The length of the string, in bytes. */ final native long strlen(long address); /** * Copies a zero (nul) terminated by array from native memory. * * This method will search for a zero byte, starting from address * and stop once a zero byte is encountered. The returned byte array does not * contain the terminating zero byte. * * @param address The address to copy the array from * @return A byte array containing the bytes copied from native memory. */ final native byte[] getZeroTerminatedByteArray(long address); /** * Copies a zero (nul) terminated by array from native memory. * * This method will search for a zero byte, starting from address * and stop once a zero byte is encountered. The returned byte array does not * contain the terminating zero byte. * * @param address The address to copy the array from * @param maxlen The maximum number of bytes to search for the nul terminator * @return A byte array containing the bytes copied from native memory. */ final native byte[] getZeroTerminatedByteArray(long address, int maxlen); /** * Copies a java byte array to native memory and appends a NUL terminating byte. * * Note A total of length + 1 bytes is written to native memory. * * @param address The address to copy to. * @param data The byte array to copy to native memory * @param offset The offset within the byte array to begin copying from * @param length The number of bytes to copy to native memory */ final native void putZeroTerminatedByteArray(long address, byte[] data, int offset, int length); /** * Creates a new Direct ByteBuffer for a native memory region. * * @param address The start of the native memory region. * @param capacity The size of the native memory region. * @return A ByteBuffer representing the native memory region. */ final native ByteBuffer newDirectByteBuffer(long address, int capacity); /** * Gets the native memory address of a direct ByteBuffer * * @param buffer A direct ByteBuffer to get the address of. * @return The native memory address of the buffer contents, or null if not a direct buffer. */ final native long getDirectBufferAddress(Buffer buffer); final native long newNativeMethod(String name, String signature, long functionContext); final native void freeNativeMethod(long handle); final native long compileNativeMethods(long[] methods); final native void freeCompiledMethods(long handle); /** * * @param clazz The java class to register the native methods on * @param handle The handle returned from compileNativeMethods * @return true if successful */ final native boolean registerNativeMethods(Class clazz, long handle); final native void unregisterNativeMethods(Class clazz); final native long getSaveErrnoFunction(); final native int getJNIVersion(); final native long getJavaVM(); final native void fatalError(String msg); final native Class defineClass(String name, Object loader, byte[] buf, int off, int len); final native Class defineClass(String name, Object loader, ByteBuffer buf); final native Object allocObject(Class clazz); final native int registerNatives(Class clazz, long methods, int methodCount); final native int unregisterNatives(Class clazz); } jffi-1.0.2/src/com/kenai/jffi/Library.java0000644000175000017500000001356411424636215020224 0ustar twernertwerner/* * Copyright (C) 2008, 2009 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ package com.kenai.jffi; import java.lang.ref.WeakReference; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * Represents a native library */ public final class Library { /** A cache of opened libraries */ private static final Map> cache = new ConcurrentHashMap>(); /** A lock used to serialize all dlopen/dlsym calls */ private static final Object lock = new Object(); /** Stores the last error returned by a dlopen or dlsym call */ private static final ThreadLocal lastError = new ThreadLocal(); /** A handle to the current process */ private static final class DefaultLibrary { private static final Library INSTANCE = new Library(null, dlopen(null, LAZY | GLOBAL)); } /** Perform lazy binding. Only resolve symbols as needed */ public static final int LAZY = Foreign.RTLD_LAZY; /** Resolve all symbols when loading the library */ public static final int NOW = Foreign.RTLD_NOW; /** Symbols in this library are not made availabl to other libraries */ public static final int LOCAL = Foreign.RTLD_LOCAL; /** All symbols in the library are made available to other libraries */ public static final int GLOBAL = Foreign.RTLD_GLOBAL; /** The native dl/LoadLibrary handle */ private final long handle; /** The name of this Library */ private final String name; /** * Internal wrapper around dlopen. * * If the library open fails, then this stores the native error in a thread * local variable for later retrieval. * * @param name The name of the library to open * @param flags The flags to pass to dlopen * @return The native handle for the opened library, or 0 if it failed to open. */ private static final long dlopen(String name, int flags) { final Foreign foreign = Foreign.getInstance(); try { return foreign.dlopen(name, flags); } catch (UnsatisfiedLinkError ex) { lastError.set(ex.getMessage()); return 0L; } } /** * Gets a handle to the default library. * * @return A Library instance representing the default library. */ public static final Library getDefault() { return DefaultLibrary.INSTANCE; } /** * Gets a handle for the named library. * * @param name The name or path of the library to open. * @param flags The library flags (e.g. LAZY, NOW, LOCAL, GLOBAL) * @return A Library instance representing the named library, or * null if the library could not be opened. */ public static final Library getCachedInstance(String name, int flags) { if (name == null) { return getDefault(); } WeakReference ref = cache.get(name); Library lib = ref != null ? ref.get() : null; if (lib != null) { return lib; } lib = openLibrary(name, flags); if (lib == null) { return null; } cache.put(name, new WeakReference(lib)); return lib; } /** * Gets a handle for the named library. * * Note This will not cache the instance, nor will it return a cached * instance. Only use when you really need a new handle for the library. * * @param name The name or path of the library to open. * @param flags The library flags (e.g. LAZY, NOW, LOCAL, GLOBAL) * @return A Library instance representing the named library, or * null if the library cannot be opened. */ public static final Library openLibrary(String name, int flags) { // dlopen on some OS does not like flags=0, so set to sensible defaults if (flags == 0) { flags = LAZY | LOCAL; } final long address = dlopen(name, flags); return address != 0L ? new Library(name, address) : null; } private Library(String name, long address) { this.name = name; this.handle = address; } /** * Gets the address of a symbol within the Library. * * @param name The name of the symbol to locate. * @return The address of the symbol within the current address space. */ public final long getSymbolAddress(String name) { final Foreign foreign = Foreign.getInstance(); try { return foreign.dlsym(handle, name); } catch (UnsatisfiedLinkError ex) { lastError.set(foreign.dlerror()); return 0; } } /** * Gets the current error string from dlopen/LoadLibrary. * * @return A String describing the last error. */ public static final String getLastError() { String error = lastError.get(); return error != null ? error : "unknown"; } @Override protected void finalize() throws Throwable { try { if (handle != 0L) { Foreign.getInstance().dlclose(handle); } } finally { super.finalize(); } } } jffi-1.0.2/src/com/kenai/jffi/PageManager.java0000644000175000017500000001020611424636215020755 0ustar twernertwerner/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ package com.kenai.jffi; /** * Manages allocation, disposal and protection of native memory pages */ abstract public class PageManager { /** The memory should be executable */ public static final int PROT_EXEC = Foreign.PROT_EXEC; /** The memory should be readable */ public static final int PROT_READ = Foreign.PROT_READ; /** The memory should be writable */ public static final int PROT_WRITE = Foreign.PROT_WRITE; private static final class SingletonHolder { public static final PageManager INSTANCE = Platform.getPlatform().getOS() == Platform.OS.WINDOWS ? new Windows() : new Unix(); } /** * Gets the page manager for the current platform. * * @return An instance of PageManager */ public static final PageManager getInstance() { return SingletonHolder.INSTANCE; } /** * Gets the system page size. * * @return The size of a page on the current system, in bytes. */ public final long pageSize() { return Foreign.getInstance().pageSize(); } /** * Allocates native memory pages. * * The memory allocated is aligned on a page boundary, and the size of the * allocated memory is npages * {@link #pageSize}. * * @param npages The number of pages to allocate. * @param protection The initial protection for the page. This must be a * bitmask of {@link #PROT_READ}, {@link #PROT_WRITE} and {@link #PROT_EXEC}. * * @return The native address of the allocated memory. */ public abstract long allocatePages(int npages, int protection); /** * Free pages allocated via {@link #allocatePages } * * @param address The memory address as returned from {@link #allocatePages} * @param npages The number of pages to free. */ public abstract void freePages(long address, int npages); /** * Sets the protection mask on a memory region. * * @param address The start of the memory region. * @param npages The number of pages to protect. * @param protection The protection mask. */ public abstract void protectPages(long address, int npages, int protection); static final class Unix extends PageManager { @Override public long allocatePages(int npages, int protection) { long sz = npages * pageSize(); return Foreign.getInstance().mmap(0, sz, protection, Foreign.MAP_ANON | Foreign.MAP_PRIVATE, -1, 0); } @Override public void freePages(long address, int npages) { Foreign.getInstance().munmap(address, npages * pageSize()); } @Override public void protectPages(long address, int npages, int protection) { Foreign.getInstance().mprotect(address, npages * pageSize(), protection); } } static final class Windows extends PageManager { public Windows() { } @Override public long allocatePages(int npages, int protection) { throw new UnsupportedOperationException("Not supported yet."); } @Override public void freePages(long address, int npages) { throw new UnsupportedOperationException("Not supported yet."); } @Override public void protectPages(long address, int npages, int protection) { throw new UnsupportedOperationException("Not supported yet."); } } } jffi-1.0.2/src/com/kenai/jffi/MemoryIO.java0000644000175000017500000007070211424636215020315 0ustar twernertwerner/* * Copyright (C) 2008, 2009 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ package com.kenai.jffi; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * Provides facilities to access native memory from java. */ public abstract class MemoryIO { /** A handle to the JNI accessor */ private final Foreign foreign = Foreign.getInstance(); /** Holds a single instance of MemoryIO */ private static final class SingletonHolder { private static final MemoryIO INSTANCE = newMemoryIO(); } /** * Gets an instance of MemoryIO that can be used to access native memory. * * @return A MemoryIO instance. */ public static MemoryIO getInstance() { return SingletonHolder.INSTANCE; } /* Restrict construction of instances to subclasses defined in this class only */ private MemoryIO() {} /** * Creates a new instance of MemoryIO optimized for the current platform. * * @return An instance of MemoryIO */ private static final MemoryIO newMemoryIO() { try { // Use sun.misc.Unsafe unless explicitly disabled by the user, or not available return !Boolean.getBoolean("jffi.unsafe.disabled") && isUnsafeAvailable() ? newUnsafeImpl() : newNativeImpl(); } catch (Throwable t) { return newNativeImpl(); } } /* * The new calls are wrapped in methods, so the classes are not referenced * until the method is called. This means only one implementation class * is ever loaded, and hotspot can inline non-final functions implemented * in the subclass. */ private static final MemoryIO newNativeImpl() { return Platform.getPlatform().addressSize() == 32 ? newNativeImpl32() : newNativeImpl64(); } /** * Creates a new JNI implementation of MemoryIO optimized for 32 bit platforms * * @return An instance of MemoryIO */ private static final MemoryIO newNativeImpl32() { return new NativeImpl32();} /** * Creates a new JNI implementation of MemoryIO optimized for 64 bit platforms * * @return An instance of MemoryIO */ private static final MemoryIO newNativeImpl64() { return new NativeImpl64();} /** * Creates a new sun.misc.Unsafe implementation of MemoryIO * * @return An instance of MemoryIO */ private static final MemoryIO newUnsafeImpl() { return Platform.getPlatform().addressSize() == 32 ? newUnsafeImpl32() : newUnsafeImpl64(); } /** * Creates a new sun.misc.Unsafe implementation of MemoryIO optimized for 32 bit platforms * * @return An instance of MemoryIO */ private static final MemoryIO newUnsafeImpl32() { return new UnsafeImpl32(); } /** * Creates a new sun.misc.Unsafe implementation of MemoryIO optimized for 64 bit platforms * * @return An instance of MemoryIO */ private static final MemoryIO newUnsafeImpl64() { return new UnsafeImpl64(); } /** * Reads an 8 bit integer from a native memory location. * * @param address The memory location to get the value from. * @return A byte containing the value. */ public abstract byte getByte(long address); /** * Reads a 16 bit integer from a native memory location. * * @param address The memory location to get the value from. * @return A short containing the value. */ public abstract short getShort(long address); /** * Reads a 32 bit integer from a native memory location. * * @param address The memory location to get the value from. * @return An int containing the value. */ public abstract int getInt(long address); /** * Reads a 64 bit integer from a native memory location. * * @param address The memory location to get the value from. * @return A long containing the value. */ public abstract long getLong(long address); /** * Reads a 32 bit floating point value from a native memory location. * * @param address The memory location to get the value from. * @return A float containing the value. */ public abstract float getFloat(long address); /** * Reads a 64 bit floating point value from a native memory location. * * @param address The memory location to get the value from. * @return A double containing the value. */ public abstract double getDouble(long address); /** * Reads a native memory address from a native memory location. * * @param address The memory location to get the value from. * @return A long containing the value. */ public abstract long getAddress(long address); /** * Writes an 8 bit integer value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ public abstract void putByte(long address, byte value); /** * Writes a 16 bit integer value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ public abstract void putShort(long address, short value); /** * Writes a 32 bit integer value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ public abstract void putInt(long address, int value); /** * Writes a 64 bit integer value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ public abstract void putLong(long address, long value); /** * Writes a 32 bit floating point value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ public abstract void putFloat(long address, float value); /** * Writes a 64 bit floating point value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ public abstract void putDouble(long address, double value); /** * Writes a native memory address value to a native memory location. * * @param address The memory location to put the value. * @param value The value to write to memory. */ public abstract void putAddress(long address, long value); /** * Copies contents of a native memory location to another native memory location. * * @param src The source memory address. * @param dst The destination memory address. * @param size The number of bytes to copy. */ public final void copyMemory(long src, long dst, long size) { if (dst + size < src || src + size < dst) { // Use intrinsic copyMemory if regions do not overlap _copyMemory(src, dst, size); } else { foreign.memmove(dst, src, size); } } /** * Copies contents of a native memory location to another native memory location. * * @param src The source memory address. * @param dst The destination memory address. * @param size The number of bytes to copy. */ abstract void _copyMemory(long src, long dst, long size); /** * Sets a region of native memory to a specific byte value. * * @param address The address of start of the native memory. * @param size The number of bytes to set. * @param value The value to set the native memory to. */ public abstract void setMemory(long address, long size, byte value); /** * Copies bytes from one memory location to another. * * The memory areas * * @param dst The destination memory address. * @param src The source memory address. * @param size The number of bytes to copy. */ public final void memcpy(long dst, long src, long size) { _copyMemory(src, dst, size); } /** * Copies potentially overlapping memory areas. * * @param dst The destination memory address. * @param src The source memory address. * @param size The number of bytes to copy. */ public final void memmove(long dst, long src, long size) { foreign.memmove(dst, src, size); } /** * Sets a region of native memory to a specific byte value. * * @param address The address of start of the native memory. * @param value The value to set the native memory to. * @param size The number of bytes to set. */ public final void memset(long address, int value, long size) { setMemory(address, size, (byte) value); } /** * Writes a java byte array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ public final void putByteArray(long address, byte[] data, int offset, int length) { foreign.putByteArray(address, data, offset, length); } /** * Reads a java byte array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ public final void getByteArray(long address, byte[] data, int offset, int length) { foreign.getByteArray(address, data, offset, length); } /** * Writes a java char array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ public final void putCharArray(long address, char[] data, int offset, int length) { foreign.putCharArray(address, data, offset, length); } /** * Reads a java char array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ public final void getCharArray(long address, char[] data, int offset, int length) { foreign.getCharArray(address, data, offset, length); } /** * Writes a java short array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ public final void putShortArray(long address, short[] data, int offset, int length) { foreign.putShortArray(address, data, offset, length); } /** * Reads a java short array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ public final void getShortArray(long address, short[] data, int offset, int length) { foreign.getShortArray(address, data, offset, length); } /** * Writes a java int array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ public final void putIntArray(long address, int[] data, int offset, int length) { foreign.putIntArray(address, data, offset, length); } /** * Reads a java int array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ public final void getIntArray(long address, int[] data, int offset, int length) { foreign.getIntArray(address, data, offset, length); } /** * Writes a java long array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ public final void putLongArray(long address, long[] data, int offset, int length) { foreign.putLongArray(address, data, offset, length); } /** * Reads a java long array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ public final void getLongArray(long address, long[] data, int offset, int length) { foreign.getLongArray(address, data, offset, length); } /** * Writes a java double array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ public final void putFloatArray(long address, float[] data, int offset, int length) { foreign.putFloatArray(address, data, offset, length); } /** * Reads a java float array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ public final void getFloatArray(long address, float[] data, int offset, int length) { foreign.getFloatArray(address, data, offset, length); } /** * Writes a java double array to native memory. * * @param address The native memory address to copy the array to. * @param data The java array to copy. * @param offset The offset within the array to start copying from. * @param length The number of array elements to copy. */ public final void putDoubleArray(long address, double[] data, int offset, int length) { foreign.putDoubleArray(address, data, offset, length); } /** * Reads a java double array from native memory. * * @param address The native memory address to copy the array from. * @param data The java array to copy. * @param offset The offset within the array to start copying to. * @param length The number of array elements to copy. */ public final void getDoubleArray(long address, double[] data, int offset, int length) { foreign.getDoubleArray(address, data, offset, length); } /** * Allocates native memory. * * @param size The number of bytes of memory to allocate * @param clear Whether the memory should be cleared (each byte set to zero). * @return The native address of the allocated memory. */ public final long allocateMemory(long size, boolean clear) { return foreign.allocateMemory(size, clear); } /** * Releases memory allocated via {@link allocateMemory} back to the system. * * @param address The address of the memory to release. */ public final void freeMemory(long address) { foreign.freeMemory(address); } /** * Gets the length of a native ascii or utf-8 string. * * @param address The native address of the string. * @return The length of the string, in bytes. */ public final long getStringLength(long address) { return foreign.strlen(address); } /** * Reads a byte array from native memory, stopping when a zero byte is found. * * This can be used to read ascii or utf-8 strings from native memory. * * @param address The address to read the data from. * @return The byte array containing a copy of the native data. Any zero * byte is stripped from the end. */ public final byte[] getZeroTerminatedByteArray(long address) { return foreign.getZeroTerminatedByteArray(address); } /** * Reads a byte array from native memory, stopping when a zero byte is found, * or the maximum length is reached. * * This can be used to read ascii or utf-8 strings from native memory. * * @param address The address to read the data from. * @param maxlen The limit of the memory area to scan for a zero byte. * @return The byte array containing a copy of the native data. Any zero * byte is stripped from the end. */ public final byte[] getZeroTerminatedByteArray(long address, int maxlen) { return foreign.getZeroTerminatedByteArray(address, maxlen); } @Deprecated public final byte[] getZeroTerminatedByteArray(long address, long maxlen) { return foreign.getZeroTerminatedByteArray(address, (int) maxlen); } /** * Copies a java byte array to native memory and appends a NUL terminating byte. * * Note A total of length + 1 bytes is written to native memory. * * @param address The address to copy to. * @param data The byte array to copy to native memory * @param offset The offset within the byte array to begin copying from * @param length The number of bytes to copy to native memory */ public final void putZeroTerminatedByteArray(long address, byte[] data, int offset, int length) { foreign.putZeroTerminatedByteArray(address, data, offset, length); } /** * Finds the location of a byte value in a native memory region. * * @param address The native memory address to start searching from. * @param value The value to search for. * @return The offset from the memory address of the value, if found, else -1 (minus one). */ public final long indexOf(long address, byte value) { final long location = foreign.memchr(address, value, Integer.MAX_VALUE); return location != 0 ? location - address : -1; } /** * Finds the location of a byte value in a native memory region. * * @param address The native memory address to start searching from. * @param value The value to search for. * @param maxlen The maximum number of bytes to search. * @return The offset from the memory address of the value, if found, else -1 (minus one). */ public final long indexOf(long address, byte value, int maxlen) { final long location = foreign.memchr(address, value, maxlen); return location != 0 ? location - address : -1; } /** * Creates a new Direct ByteBuffer for a native memory region. * * @param address The start of the native memory region. * @param capacity The size of the native memory region. * @return A ByteBuffer representing the native memory region. */ public final java.nio.ByteBuffer newDirectByteBuffer(long address, int capacity) { return foreign.newDirectByteBuffer(address, capacity); } /** * Gets the native memory address of a direct ByteBuffer * * @param buffer A direct ByteBuffer to get the address of. * @return The native memory address of the buffer contents, or null if not a direct buffer. */ public final long getDirectBufferAddress(java.nio.Buffer buffer) { return foreign.getDirectBufferAddress(buffer); } /** * An implementation of MemoryIO using JNI methods. */ private static abstract class NativeImpl extends MemoryIO { protected static final Foreign foreign = Foreign.getInstance(); public final byte getByte(long address) { return foreign.getByte(address); } public final short getShort(long address) { return foreign.getShort(address); } public final int getInt(long address) { return foreign.getInt(address); } public final long getLong(long address) { return foreign.getLong(address); } public final float getFloat(long address) { return foreign.getFloat(address); } public final double getDouble(long address) { return foreign.getDouble(address); } public final void putByte(long address, byte value) { foreign.putByte(address, value); } public final void putShort(long address, short value) { foreign.putShort(address, value); } public final void putInt(long address, int value) { foreign.putInt(address, value); } public final void putLong(long address, long value) { foreign.putLong(address, value); } public final void putFloat(long address, float value) { foreign.putFloat(address, value); } public final void putDouble(long address, double value) { foreign.putDouble(address, value); } public final void setMemory(long address, long size, byte value) { foreign.setMemory(address, size, value); } public final void _copyMemory(long src, long dst, long size) { foreign.copyMemory(src, dst, size); } } /** * A 32 bit optimized implementation of MemoryIO using JNI. */ private static final class NativeImpl32 extends NativeImpl { public final long getAddress(long address) { return foreign.getInt(address); } public final void putAddress(long address, long value) { foreign.putInt(address, (int) value); } } /** * A 64 bit optimized implementation of MemoryIO using JNI. */ private static final class NativeImpl64 extends NativeImpl { public final long getAddress(long address) { return foreign.getAddress(address); } public final void putAddress(long address, long value) { foreign.putAddress(address, value); } } /** * An implementation of MemoryIO using sun.misc.Unsafe */ private static abstract class UnsafeImpl extends MemoryIO { protected static sun.misc.Unsafe unsafe = sun.misc.Unsafe.class.cast(getUnsafe()); private static final Object getUnsafe() { try { Class sunUnsafe = Class.forName("sun.misc.Unsafe"); Field f = sunUnsafe.getDeclaredField("theUnsafe"); f.setAccessible(true); return f.get(sunUnsafe); } catch (Exception ex) { throw new RuntimeException(ex); } } public final byte getByte(long address) { return unsafe.getByte(address); } public final short getShort(long address) { return unsafe.getShort(address); } public final int getInt(long address) { return unsafe.getInt(address); } public final long getLong(long address) { return unsafe.getLong(address); } public final float getFloat(long address) { return unsafe.getFloat(address); } public final double getDouble(long address) { return unsafe.getDouble(address); } public final void putByte(long address, byte value) { unsafe.putByte(address, value); } public final void putShort(long address, short value) { unsafe.putShort(address, value); } public final void putInt(long address, int value) { unsafe.putInt(address, value); } public final void putLong(long address, long value) { unsafe.putLong(address, value); } public final void putFloat(long address, float value) { unsafe.putFloat(address, value); } public final void putDouble(long address, double value) { unsafe.putDouble(address, value); } public final void _copyMemory(long src, long dst, long size) { unsafe.copyMemory(src, dst, size); } public final void setMemory(long src, long size, byte value) { unsafe.setMemory(src, size, value); } } /** * A 32 bit optimized implementation of MemoryIO using sun.misc.Unsafe */ private static final class UnsafeImpl32 extends UnsafeImpl { public final long getAddress(long address) { return unsafe.getInt(address); } public final void putAddress(long address, long value) { unsafe.putInt(address, (int) value); } } /** * A 64 bit optimized implementation of MemoryIO using sun.misc.Unsafe */ private static final class UnsafeImpl64 extends UnsafeImpl { public final long getAddress(long address) { return unsafe.getAddress(address); } public final void putAddress(long address, long value) { unsafe.putAddress(address, value); } } /** * Verifies that there is are accessor functions (get,put) for a particular * primitive type in the sun.misc.Unsafe class. * * @param unsafeClass The class of sun.misc.Unsafe * @param primitive The class of the primitive type. * @throws NoSuchMethodException If no accessors for that primitive type exist. */ @SuppressWarnings("unchecked") private static final void verifyAccessor(Class unsafeClass, Class primitive) throws NoSuchMethodException { String primitiveName = primitive.getSimpleName(); String typeName = primitiveName.substring(0, 1).toUpperCase() + primitiveName.substring(1); Method get = unsafeClass.getDeclaredMethod("get" + typeName, new Class[] { long.class }); if (!get.getReturnType().equals(primitive)) { throw new NoSuchMethodException("Incorrect return type for " + get.getName()); } unsafeClass.getDeclaredMethod("put" + typeName, new Class[] { long.class, primitive}); } /** * Determines the best Unsafe implementation to use. Some platforms (e.g. gcj) * do not have all the methods that sun.misc.Unsafe does, so we need to check for them. * * This also handles the case where sun.misc.Unsafe vanishes from future versions * of the JVM. * @return */ @SuppressWarnings("unchecked") static final boolean isUnsafeAvailable() { try { Class sunClass = Class.forName("sun.misc.Unsafe"); // // Verify that all the accessor methods we need are there // Class[] primitiveTypes = { byte.class, short.class, int.class, long.class, float.class, double.class }; for (Class type : primitiveTypes) { verifyAccessor(sunClass, type); } // // Check for any other methods we need // sunClass.getDeclaredMethod("getAddress", new Class[] { long.class }); sunClass.getDeclaredMethod("putAddress", new Class[] { long.class, long.class }); sunClass.getDeclaredMethod("allocateMemory", new Class[] { long.class }); sunClass.getDeclaredMethod("freeMemory", new Class[] { long.class }); return true; } catch (Throwable ex) { return false; } } } jffi-1.0.2/src/com/kenai/jffi/Internals.java0000644000175000017500000000170611424636215020552 0ustar twernertwerner/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ package com.kenai.jffi; /** * Retrieves metadata about jffi C internals */ public final class Internals { private Internals() { } public static final long getErrnoSaveFunction() { return Foreign.getInstance().getSaveErrnoFunction(); } } jffi-1.0.2/src/com/kenai/jffi/Struct.java0000644000175000017500000000231411424636215020073 0ustar twernertwerner/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ package com.kenai.jffi; /** * Describes the layout of a C struct */ public final class Struct extends Aggregate { /* Keep a strong reference to the field types so they do not GCed */ private final Type[] fields; /** * Creates a new C struct layout description. * * @param fields The fields contained in the struct. */ public Struct(Type... fields) { super(Foreign.getInstance().newStruct(Type.nativeHandles(fields), false)); this.fields = (Type[]) fields.clone(); } } jffi-1.0.2/src/com/kenai/jffi/ClosureManager.java0000644000175000017500000000733711424636215021530 0ustar twernertwerner/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ package com.kenai.jffi; import java.lang.ref.Reference; import java.lang.ref.SoftReference; import java.util.Map; import java.util.WeakHashMap; /** * Allocates and manages the lifecycle of native closures (aka callbacks) */ public class ClosureManager { /** * ClosurePool instances are linked via a SoftReference in the lookup map, so * when all closure instances that that were allocated from the ClosurePool have been * reclaimed, and there is memory pressure, the native closure pool can be freed. * This will allow the CallContext instance to also be collected if it is not * strongly referenced elsewhere, and ejected from the {@link CallContextCache} */ private final Map> poolMap = new WeakHashMap>(); /** Holder class to do lazy allocation of the ClosureManager instance */ private static final class SingletonHolder { static final ClosureManager INSTANCE = new ClosureManager(); } /** * Gets the global instance of the ClosureManager * * @return An instance of a ClosureManager */ public static final ClosureManager getInstance() { return SingletonHolder.INSTANCE; } /** Constructs a ClosureManager */ private ClosureManager() { } /** * Wraps a java object that implements the {@link Closure} interface in a * native closure. * * @param closure The java object to be called when the native closure is invoked. * @param returnType The return type of the closure. * @param parameterTypes The parameter types of the closure. * @param convention The calling convention of the closure. * @return A new {@link Closure.Handle} instance. */ public final Closure.Handle newClosure(Closure closure, Type returnType, Type[] parameterTypes, CallingConvention convention) { return newClosure(closure, CallContextCache.getInstance().getCallContext(returnType, parameterTypes, convention)); } /** * Wraps a java object that implements the {@link Closure} interface in a * native closure. * * @param closure The java object to be called when the native closure is invoked. * @param returnType The return type of the closure. * @param parameterTypes The parameter types of the closure. * @param convention The calling convention of the closure. * @return A new {@link Closure.Handle} instance. */ public final Closure.Handle newClosure(Closure closure, CallContext callContext) { ClosurePool pool = getClosurePool(callContext); return pool.newClosureHandle(closure); } private final synchronized ClosurePool getClosurePool(CallContext callContext) { Reference ref = poolMap.get(callContext); ClosurePool pool; if (ref != null && (pool = ref.get()) != null) { return pool; } poolMap.put(callContext, new SoftReference(pool = new ClosurePool(callContext))); return pool; } } jffi-1.0.2/src/com/kenai/jffi/Function.java0000644000175000017500000001376311424636215020406 0ustar twernertwerner/* * Copyright (C) 2008, 2009 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ package com.kenai.jffi; /** * Native function invocation context * * This class holds all the information that JFFI needs to correctly call a * native function. */ public final class Function implements CallInfo { /** The native address of the context */ private final long contextAddress; /** The address of the function */ private final long functionAddress; /** The number of parameters this function takes */ private final int parameterCount; /** The size of buffer required when packing parameters */ private final int rawParameterSize; /** The return type of this function */ private final Type returnType; /** The parameter types of this function */ private final Type[] paramTypes; /** Whether the native context has been freed yet */ private volatile boolean disposed = false; /** * Creates a new instance of Function with default calling convention. * * @param address The native address of the function to invoke. * @param returnType The return type of the native function. * @param paramTypes The parameter types the function accepts. */ public Function(long address, Type returnType, Type... paramTypes) { this(address, returnType, paramTypes, CallingConvention.DEFAULT, true); } /** * Creates a new instance of Function. * * Function instances created with this constructor will save the * C errno contents after each call. * * @param address The native address of the function to invoke. * @param returnType The return type of the native function. * @param paramTypes The parameter types the function accepts. * @param convention The calling convention of the function. */ public Function(long address, Type returnType, Type[] paramTypes, CallingConvention convention) { this(address, returnType, paramTypes, convention, true); } /** * Creates a new instance of Function. * * @param address The native address of the function to invoke. * @param returnType The return type of the native function. * @param paramTypes The parameter types the function accepts. * @param convention The calling convention of the function. * @param saveErrno Whether the errno should be saved or not */ public Function(long address, Type returnType, Type[] paramTypes, CallingConvention convention, boolean saveErrno) { this.functionAddress = address; final int flags = (!saveErrno ? Foreign.F_NOERRNO : 0) | (convention == CallingConvention.STDCALL ? Foreign.F_STDCALL : Foreign.F_DEFAULT); final long h = Foreign.getInstance().newFunction(address, returnType.handle(), Type.nativeHandles(paramTypes), flags); if (h == 0) { throw new RuntimeException("Failed to create native function"); } this.contextAddress = h; // // Keep references to the return and parameter types so they do not get // garbage collected // this.returnType = returnType; this.paramTypes = (Type[]) paramTypes.clone(); this.parameterCount = paramTypes.length; this.rawParameterSize = Foreign.getInstance().getFunctionRawParameterSize(h); } /** * Gets the number of parameters the native function accepts. * * @return The number of parameters the native function accepts. */ public final int getParameterCount() { return parameterCount; } /** * Gets the number of bytes required to pack all the parameters this function * accepts, into a region of memory. * * @return The number of bytes required to store all paraameters of this function. */ public final int getRawParameterSize() { return rawParameterSize; } /** * Gets the address of the function context. * * @return The address of the native function context struct. */ final long getContextAddress() { return contextAddress; } /** * Gets the address of the function. * * @return The address of the native function. */ public final long getFunctionAddress() { return functionAddress; } /** * Gets the native return type of this function. * * @return The native return type of this function. */ public final Type getReturnType() { return returnType; } /** * Gets the type of a parameter. * * @param index The index of the parameter in the function signature * @return The Type of the parameter. */ public final Type getParameterType(int index) { return paramTypes[index]; } public synchronized final void dispose() { if (disposed) { throw new RuntimeException("function already freed"); } Foreign.getInstance().freeFunction(contextAddress); disposed = true; } @Override protected void finalize() throws Throwable { try { if (contextAddress != 0 && !disposed) { Foreign.getInstance().freeFunction(contextAddress); } } catch (Throwable t) { t.printStackTrace(System.err); } finally { super.finalize(); } } } jffi-1.0.2/src/com/kenai/jffi/Closure.java0000644000175000017500000001414011424636215020223 0ustar twernertwerner/* * Copyright (C) 2008, 2009 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ package com.kenai.jffi; /** * Represents a native closure. * * A Closure is implemented by java code to act as a C function pointer. */ public interface Closure { public void invoke(Buffer buffer); /** * An interface to the native callback parameter buffer. */ public static interface Buffer { /** * Gets the value of an 8 bit integer parameter. * * @param index The parameter index * @return An 8 bit integer value. */ byte getByte(int index); /** * Gets the value of a 16 bit integer parameter. * * @param index The parameter index * @return A 16 bit integer value. */ short getShort(int index); /** * Gets the value of a 32 bit integer parameter. * * @param index The parameter index * @return A 32 bit integer value. */ int getInt(int index); /** * Gets the value of a 64 bit integer parameter. * * @param index The parameter index * @return A 64 bit integer value. */ long getLong(int index); /** * Gets the value of a 32 bit floating point parameter. * * @param index The parameter index * @return A 32 bit floating point value. */ float getFloat(int index); /** * Gets the value of a 64 bit floating point parameter. * * @param index The parameter index * @return A 64 bit floating point value. */ double getDouble(int index); /** * Gets the value of a native pointer parameter. * * @param index The parameter index * @return A native memory address. */ long getAddress(int index); /** * Gets the address of a struct parameter that is passed by value. * * @param index The parameter index * @return A native memory address. */ long getStruct(int index); /** * Sets the closure return value to an 8 bit integer value. * * @param value The 8 bit integer value to return from the closure. */ void setByteReturn(byte value); /** * Sets the closure return value to a 16 bit integer value. * * @param value The 16 bit integer value to return from the closure. */ void setShortReturn(short value); /** * Sets the closure return value to a 32 bit integer value. * * @param value The 32 bit integer value to return from the closure. */ void setIntReturn(int value); /** * Sets the closure return value to a 64 bit integer value. * * @param value The 64 bit integer value to return from the closure. */ void setLongReturn(long value); /** * Sets the closure return value to a 32 bit floating point value. * * @param value The 32 bit floating point value to return from the closure. */ void setFloatReturn(float value); /** * Sets the closure return value to a 64 bit floating point value. * * @param value The 64 bit floating point value to return from the closure. */ void setDoubleReturn(double value); /** * Sets the closure return value to a native pointer value. * * @param address The native pointer value to return from the closure. */ void setAddressReturn(long address); /** * Sets the closure return value to the contents of a struct * * @param address The address of a native struct to return as a struct value from the closure. */ void setStructReturn(long address); /** * Sets the closure return value to the contents of a struct * * @param data Struct data packed into a byte array to return as a struct value from the closure. * @param offset the offset within the byte array to start copying data */ void setStructReturn(byte[] data, int offset); } /** * A Handle is allocated by the {@link ClosureManager}, as a strong reference * to the native closure trampoline. */ public static interface Handle { /** * Gets the native code address of the closure. * * This can be passed into a native function that takes a function pointer. * * @return The native address of the closure code. */ long getAddress(); /** * Sets whether the closure memory should be released when the Handle is * garbage collected or not. * * @param autorelease If true, the closure memory is automatically managed, * else the closure memory must be explicitly freed. */ void setAutoRelease(boolean autorelease); /** * Releases the closure memory back to the operating system. * * Although the closure trampoline memory will normally be released when * the Handle is garbage collected, this may not happen for some * time, and is non-deterministic. This allows explicit control over * memory reclamation. */ void dispose(); @Deprecated void free(); } } jffi-1.0.2/src/com/kenai/jffi/Union.java0000644000175000017500000000230711424636215017701 0ustar twernertwerner/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ package com.kenai.jffi; /** * Describes the layout of a C union */ public final class Union extends Aggregate { /* Keep a strong reference to the field types so they do not GCed */ private final Type[] fields; /** * Creates a new C union layout description. * * @param fields The fields contained in the struct. */ public Union(Type... fields) { super(Foreign.getInstance().newStruct(Type.nativeHandles(fields), true)); this.fields = (Type[]) fields.clone(); } } jffi-1.0.2/src/com/kenai/jffi/Init.java0000644000175000017500000001361111424636215017514 0ustar twernertwerner/* * Copyright (C) 2007, 2008 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ package com.kenai.jffi; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.channels.Channels; import java.nio.channels.FileChannel; import java.nio.channels.ReadableByteChannel; import java.util.Properties; /** * Utility class to load the jffi stub library */ final class Init { private static final String bootPropertyFilename = "boot.properties"; private static final String bootLibraryPropertyName = "jffi.boot.library.path"; private static final String stubLibraryName = String.format("jffi-%d.%d", Foreign.VERSION_MAJOR, Foreign.VERSION_MINOR); private static volatile boolean loaded = false; // prevent instantiation private Init() {} /** * Loads the stub library */ static final void load() { if (loaded) { return; } final String libName = getStubLibraryName(); String bootPath = getBootPath(); if (bootPath != null && loadFromBootPath(libName, bootPath)) { return; } try { System.loadLibrary(libName); return; } catch (UnsatisfiedLinkError ex) {} loadFromJar(); } private static final String getBootPath() { String bootPath = System.getProperty(bootLibraryPropertyName); if (bootPath != null) { return bootPath; } InputStream is = Init.class.getResourceAsStream(bootPropertyFilename); if (is != null) { Properties p = new Properties(); try { p.load(is); return p.getProperty(bootLibraryPropertyName); } catch (IOException ex) { } finally { try { is.close(); } catch (IOException ex) { throw new RuntimeException(ex); } } } return null; } private static final boolean loadFromBootPath(String libName, String bootPath) { String[] dirs = bootPath.split(File.pathSeparator); for (int i = 0; i < dirs.length; ++i) { String path = new File(new File(dirs[i]), System.mapLibraryName(libName)).getAbsolutePath(); try { System.load(path); return true; } catch (UnsatisfiedLinkError ex) { } if (Platform.getPlatform().getOS() == Platform.OS.DARWIN) { String orig, ext; if (path.endsWith("dylib")) { orig = "dylib"; ext = "jnilib"; } else { orig = "jnilib"; ext = "dylib"; } try { System.load(path.substring(0, path.lastIndexOf(orig)) + ext); return true; } catch (UnsatisfiedLinkError ex) { } } } return false; } private static final void loadFromJar() { InputStream is = getStubLibraryStream(); File dstFile = null; FileOutputStream os = null; try { dstFile = File.createTempFile("jffi", null); dstFile.deleteOnExit(); os = new FileOutputStream(dstFile); ReadableByteChannel srcChannel = Channels.newChannel(is); for (long pos = 0; is.available() > 0; ) { pos += os.getChannel().transferFrom(srcChannel, pos, Math.max(4096, is.available())); } System.load(dstFile.getAbsolutePath()); } catch (IOException ex) { throw new UnsatisfiedLinkError(ex.getMessage()); } finally { try { if (os != null) { os.close(); } is.close(); } catch (IOException ex) { throw new RuntimeException(ex); } } } /** * Gets an InputStream representing the stub library image stored in * the jar file. * * @return A new InputStream */ private static final InputStream getStubLibraryStream() { String path = getStubLibraryPath(); InputStream is = Init.class.getResourceAsStream(path); // On MacOS, the stub might be named .dylib or .jnilib - cater for both if (is == null && Platform.getPlatform().getOS() == Platform.OS.DARWIN) { is = Init.class.getResourceAsStream(path.replaceAll("dylib", "jnilib")); } if (is == null) { throw new UnsatisfiedLinkError("Could not locate stub library (" + path + ") in jar file"); } return is; } /** * Gets the name of the stub library. * * @return The name of the stub library as a String */ private static final String getStubLibraryName() { return stubLibraryName; } /** * Gets the path within the jar file of the stub native library. * * @return The path of the jar file. */ private static final String getStubLibraryPath() { return "/jni/" + Platform.getPlatform().getName() + "/"+ System.mapLibraryName(stubLibraryName); } } jffi-1.0.2/src/com/kenai/jffi/Platform.java0000644000175000017500000002630211424636215020376 0ustar twernertwerner/* * Copyright (C) 2007, 2008, 2009 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ package com.kenai.jffi; /** * Convenience class to interrogate the system about various platform-specific details. */ public abstract class Platform { private final OS os; private final CPU cpu; private final int addressSize; private final long addressMask; private final int longSize; private final int javaVersionMajor; /** * The common names of operating systems. * * Note The names of the enum values are used in other parts of the * code to determine where to find the native stub library. Do not rename. */ public enum OS { /** MacOSX */ DARWIN, /** FreeBSD */ FREEBSD, /** NetBSD */ NETBSD, /** OpenBSD */ OPENBSD, /** Linux */ LINUX, /** Solaris (and OpenSolaris) */ SOLARIS, /** The evil borg operating system */ WINDOWS, /** IBM AIX */ AIX, /** IBM zOS **/ ZLINUX, /** No idea what the operating system is */ UNKNOWN; @Override public String toString() { return name().toLowerCase(); } } /** * The common names of cpu architectures. * * Note The names of the enum values are used in other parts of the * code to determine where to find the native stub library. Do not rename. */ public enum CPU { /** Intel ia32 */ I386, /** AMD 64 bit (aka EM64T/X64) */ X86_64, /** Power PC 32 bit */ PPC, /** Power PC 64 bit */ PPC64, /** Sun sparc 32 bit */ SPARC, /** Sun sparc 64 bit */ SPARCV9, /** IBM zSeries S/390 64 bit */ S390X, /** Unknown CPU */ UNKNOWN; @Override public String toString() { return name().toLowerCase(); } } /** * Holds a single, lazily loaded instance of Platform */ private static final class SingletonHolder { static final Platform PLATFORM = determinePlatform(determineOS()); } /** * Determines the operating system jffi is running on * * @return An member of the OS enum. */ private static final OS determineOS() { String osName = System.getProperty("os.name").split(" ")[0].toLowerCase(); if (osName.startsWith("mac") || osName.startsWith("darwin")) { return OS.DARWIN; } else if (osName.startsWith("linux")) { return OS.LINUX; } else if (osName.startsWith("sunos") || osName.startsWith("solaris")) { return OS.SOLARIS; } else if (osName.startsWith("aix")) { return OS.AIX; } else if (osName.startsWith("openbsd")) { return OS.OPENBSD; } else if (osName.startsWith("freebsd")) { return OS.FREEBSD; } else if (osName.startsWith("windows")) { return OS.WINDOWS; } else { throw new ExceptionInInitializerError("Unsupported operating system"); } } /** * Determines the Platform that best describes the OS * * @param os The operating system. * @return An instance of Platform */ private static final Platform determinePlatform(OS os) { switch (os) { case DARWIN: return new Darwin(); case WINDOWS: return new Windows(); case UNKNOWN: throw new ExceptionInInitializerError("Unsupported operating system"); default: return new Default(os); } } /** * Determines the CPU architecture the JVM is running on. * * This normalizes all the variations that are equivalent (e.g. i386, x86, i86pc) * into a common cpu type. * * @return A member of the CPU enum. */ private static final CPU determineCPU() { String archString = System.getProperty("os.arch", "unknown").toLowerCase(); if ("x86".equals(archString) || "i386".equals(archString) || "i86pc".equals(archString)) { return CPU.I386; } else if ("x86_64".equals(archString) || "amd64".equals(archString)) { return CPU.X86_64; } else if ("ppc".equals(archString) || "powerpc".equals(archString)) { return CPU.PPC; } else if ("powerpc64".equals(archString)) { return CPU.PPC64; } // Try to find by lookup up in the CPU list try { return CPU.valueOf(archString.toUpperCase()); } catch (IllegalArgumentException ex) { throw new ExceptionInInitializerError("Unsupported CPU architecture: " + archString); } } /** * Constructs a new Platform instance. * * @param os The current operating system. */ private Platform(OS os) { this.os = os; this.cpu = determineCPU(); int dataModel = Integer.getInteger("sun.arch.data.model", 0); // // If we're running on a broken JVM that doesn't support the sun.arch.data.model property // try to deduce the data model using the CPU type. // if (dataModel != 32 && dataModel != 64) { switch (cpu) { case I386: case PPC: case SPARC: dataModel = 32; break; case X86_64: case PPC64: case SPARCV9: case S390X: dataModel = 64; break; default: throw new ExceptionInInitializerError("Cannot determine cpu address size"); } } addressSize = dataModel; addressMask = addressSize == 32 ? 0xffffffffL : 0xffffffffffffffffL; longSize = os == OS.WINDOWS ? 32 : addressSize; int version = 5; try { String versionString = System.getProperty("java.version"); if (versionString != null) { String[] v = versionString.split("\\."); version = Integer.valueOf(v[1]); } } catch (Exception ex) { throw new ExceptionInInitializerError("Could not determine java version"); } javaVersionMajor = version; } /** * Gets the current Platform * * @return The current platform. */ public static final Platform getPlatform() { return SingletonHolder.PLATFORM; } /** * Gets the current Operating System. * * @return A OS value representing the current Operating System. */ public final OS getOS() { return os; } /** * Gets the current processor architecture the JVM is running on. * * @return A CPU value representing the current processor architecture. */ public final CPU getCPU() { return cpu; } /** * Gets the version of the Java Virtual Machine (JVM) jffi is running on. * * @return A number representing the java version. e.g. 5 for java 1.5, 6 for java 1.6 */ public final int getJavaMajorVersion() { return javaVersionMajor; } /** * Gets the size of a C 'long' on the native platform. * * @return the size of a long in bits */ public final int longSize() { return longSize; } /** * Gets the size of a C address/pointer on the native platform. * * @return the size of a pointer in bits */ public final int addressSize() { return addressSize; } /** * Gets the 32/64bit mask of a C address/pointer on the native platform. * * @return the size of a pointer in bits */ public final long addressMask() { return addressMask; } /** * Gets the name of this Platform. * * @return The name of this platform. */ public String getName() { String osName = System.getProperty("os.name").split(" ")[0]; return getCPU().name().toLowerCase() + "-" + osName; } /** * Maps from a generic library name (e.g. "c") to the platform specific library name. * * @param libName The library name to map * @return The mapped library name. */ public String mapLibraryName(String libName) { // // A specific version was requested - use as is for search // if (libName.matches(getLibraryNamePattern())) { return libName; } return System.mapLibraryName(libName); } /** * Gets the regex string used to match platform-specific libraries * @return */ public String getLibraryNamePattern() { return "lib.*\\.so.*$"; } /** * Checks if the current platform is supported by JFFI. * * @return true if the platform is supported, else false. */ public boolean isSupported() { // // Call a function in the stub library - this will throw an // exception if there is no stub lib for this platform. // int version = Foreign.getInstance().getVersion(); if ((version & 0xffff00) == (Foreign.VERSION_MAJOR << 16 | Foreign.VERSION_MINOR << 8)) { return true; } throw new UnsatisfiedLinkError("Incorrect native library version"); } private static final class Default extends Platform { public Default(OS os) { super(os); } } /** * A {@link Platform} subclass representing the MacOS system. */ private static final class Darwin extends Platform { public Darwin() { super(OS.DARWIN); } @Override public String mapLibraryName(String libName) { // // A specific version was requested - use as is for search // if (libName.matches(getLibraryNamePattern())) { return libName; } return "lib" + libName + ".dylib"; } @Override public String getLibraryNamePattern() { return "lib.*\\.(dylib|jnilib)$"; } @Override public String getName() { return "Darwin"; } } /** * A {@link Platform} subclass representing the Windows system. */ private static class Windows extends Platform { public Windows() { super(OS.WINDOWS); } @Override public String getLibraryNamePattern() { return ".*\\.dll$"; } } } jffi-1.0.2/src/com/kenai/jffi/Array.java0000644000175000017500000000323211424636215017665 0ustar twernertwerner/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ package com.kenai.jffi; /** * Describes the layout of a C array */ public final class Array extends Aggregate { /* Keep a strong reference to the element types so it is not GCed */ private final Type elementType; private final int length; /** * Creates a new C array layout description. * * @param fields The fields contained in the struct. */ public Array(Type elementType, int length) { super(Foreign.getInstance().newArray(elementType.handle(), length)); this.elementType = elementType; this.length = length; } /** * Returns the type of elements in the array * * @return The Type of the elements in the array */ public final Type getElementType() { return elementType; } /** * Returns the number of elements in the array * * @return The number of elements in the array */ public final int length() { return length; } } jffi-1.0.2/src/com/kenai/jffi/Type.java0000644000175000017500000001722111424636215017533 0ustar twernertwerner/* * Copyright (C) 2008, 2009 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ package com.kenai.jffi; import java.util.List; /** * Native parameter and return types. */ public abstract class Type { /** The native void type */ public static final Type VOID = builtin(NativeType.VOID); /** The native float type */ public static final Type FLOAT = builtin(NativeType.FLOAT); /** The native double type */ public static final Type DOUBLE = builtin(NativeType.DOUBLE); /** The native long double type */ public static final Type LONGDOUBLE = builtin(NativeType.LONGDOUBLE); /** The native unsigned 8 bit integer type */ public static final Type UINT8 = builtin(NativeType.UINT8); /** The native signed 8 bit integer type */ public static final Type SINT8 = builtin(NativeType.SINT8); /** The native unsigned 16 bit integer type */ public static final Type UINT16 = builtin(NativeType.UINT16); /** The native signed 16 bit integer type */ public static final Type SINT16 = builtin(NativeType.SINT16); /** The native unsigned 32 bit integer type */ public static final Type UINT32 = builtin(NativeType.UINT32); /** The native signed 32 bit integer type */ public static final Type SINT32 = builtin(NativeType.SINT32); /** The native unsigned 64 bit integer type */ public static final Type UINT64 = builtin(NativeType.UINT64); /** The native signed 64 bit integer type */ public static final Type SINT64 = builtin(NativeType.SINT64); /** The native memory address type */ public static final Type POINTER = builtin(NativeType.POINTER); /** The native unsigned char type */ public static final Type UCHAR = UINT8; /** The native signed char type */ public static final Type SCHAR = SINT8; /** The native unsigned short integer type */ public static final Type USHORT = UINT16; /** The native signed short integer type */ public static final Type SSHORT = SINT16; /** The native unsigned integer type */ public static final Type UINT = UINT32; /** The native signed integer type */ public static final Type SINT = SINT32; /** The native unsigned long integer type */ public static final Type ULONG = builtin(NativeType.ULONG); /** The native signed long integer type */ public static final Type SLONG = builtin(NativeType.SLONG); /** The native unsigned long long integer type */ public static final Type ULONG_LONG = UINT64; /** The native signed long long integer type */ public static final Type SLONG_LONG = SINT64; /** * Gets the FFI type enum value for this Type * * @return An integer representing the FFI type. */ public abstract int type(); /** * Gets the native address of the ffi_type struct for this Type * * @return The address of the ffi_type structure */ abstract long handle(); /** * Gets the size of this type. * * @return The size of this type, in bytes. */ public abstract int size(); /** * Gets the alignment of this type. * * @return The alignment of this type, in bytes. */ public abstract int alignment(); @Override public boolean equals(Object obj) { return (obj instanceof Type) && ((Type) obj).handle() == handle(); } @Override public int hashCode() { int hash = 3; hash = 67 * hash + (int) (this.handle() ^ (this.handle() >>> 32)); return hash; } /** * Converts an array of Type objects into an array of pointers to * ffi_type structures. * * @param types An array of Type objects * @return An array of native ffi_type handles. */ final static long[] nativeHandles(Type[] types) { long[] nativeTypes = new long[types.length]; for (int i = 0; i < types.length; ++i) { nativeTypes[i] = types[i].handle(); } return nativeTypes; } /** * Converts a list of Type objects into an array of pointers to * ffi_type structures. * * @param types A list of Type objects * @return An array of native ffi_type handles. */ final static long[] nativeHandles(List types) { long[] nativeTypes = new long[types.size()]; for (int i = 0; i < nativeTypes.length; ++i) { nativeTypes[i] = types.get(i).handle(); } return nativeTypes; } /** * Creates a Type instance for builtin types. * * @param type The builtin type enum. * @return A Type instance. */ private static final Type builtin(NativeType nativeType) { return new Builtin(nativeType); } /** * Types that are built-in to libffi. */ static final class Builtin extends Type { private final NativeType nativeType; private Builtin(NativeType nativeType) { this.nativeType = nativeType; } public final int type() { return BuiltinTypeInfo.find(nativeType).type; } public final long handle() { return BuiltinTypeInfo.find(nativeType).handle; } public final int size() { return BuiltinTypeInfo.find(nativeType).size; } public final int alignment() { return BuiltinTypeInfo.find(nativeType).alignment; } } /** * This is a lazy loaded cache of builtin type info, so we can still have * Type.VOID as a public static variable without it causing the * native library to load. */ private static final class BuiltinTypeInfo { public static final BuiltinTypeInfo[] typeMap; /** The FFI type of this type */ final int type; /** The size in bytes of this type */ final int size; /** The minimum alignment of this type */ final int alignment; /** The address of this type's ffi_type structure */ final long handle; static { NativeType[] nativeTypes = NativeType.values(); typeMap = new BuiltinTypeInfo[nativeTypes.length]; for (int i = 0; i < typeMap.length; ++i) { long h = Foreign.getInstance().lookupBuiltinType(nativeTypes[i].ffiType); if (h == 0L) { throw new RuntimeException("invalid native type " + nativeTypes[i]); } typeMap[i] = new BuiltinTypeInfo(h); } } static final BuiltinTypeInfo find(NativeType t) { return typeMap[t.ordinal()]; } private BuiltinTypeInfo(long handle) { if (handle == 0L) { throw new NullPointerException("null ffi_type handle"); } this.handle = handle; this.type = Foreign.getInstance().getTypeType(handle); this.size = Foreign.getInstance().getTypeSize(handle); this.alignment = Foreign.getInstance().getTypeAlign(handle); } } } jffi-1.0.2/src/com/kenai/jffi/HeapInvocationBuffer.java0000644000175000017500000004630211424636215022655 0ustar twernertwerner/* * Copyright (C) 2008, 2009 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ package com.kenai.jffi; import java.nio.ByteOrder; /** * An implementation of {@link InvocationBuffer} that packs its parameters onto * a java heap allocated buffer. */ public final class HeapInvocationBuffer implements InvocationBuffer { private static final int FFI_SIZEOF_ARG = Platform.getPlatform().addressSize() / 8; private static final int PARAM_SIZE = 8; private static final Encoder encoder = getEncoder(); private final CallInfo info; private final byte[] buffer; private ObjectBuffer objectBuffer = null; private int paramOffset = 0; private int paramIndex = 0; /** * Creates a new instance of HeapInvocationBuffer. * * @param info The call info that describes the function parameters */ public HeapInvocationBuffer(CallInfo info) { this.info = info; buffer = new byte[encoder.getBufferSize(info)]; } /** * Creates a new instance of HeapInvocationBuffer. * * @param function The function that this buffer is going to be used with. */ public HeapInvocationBuffer(Function function) { this.info = function; buffer = new byte[encoder.getBufferSize(function)]; } /** * Gets the backing array of this InvocationBuffer * * @return The backing array for this buffer. */ byte[] array() { return buffer; } /** * Gets the object buffer used to store java heap array parameters * * @return An ObjectBuffer */ ObjectBuffer objectBuffer() { return objectBuffer; } public final void putByte(final int value) { paramOffset = encoder.putByte(buffer, paramOffset, value); ++paramIndex; } public final void putShort(final int value) { paramOffset = encoder.putShort(buffer, paramOffset, value); ++paramIndex; } public final void putInt(final int value) { paramOffset = encoder.putInt(buffer, paramOffset, value); ++paramIndex; } public final void putLong(final long value) { paramOffset = encoder.putLong(buffer, paramOffset, value); ++paramIndex; } public final void putFloat(final float value) { paramOffset = encoder.putFloat(buffer, paramOffset, value); ++paramIndex; } public final void putDouble(final double value) { paramOffset = encoder.putDouble(buffer, paramOffset, value); ++paramIndex; } public final void putAddress(final long value) { paramOffset = encoder.putAddress(buffer, paramOffset, value); ++paramIndex; } private final ObjectBuffer getObjectBuffer() { if (objectBuffer == null) { objectBuffer = new ObjectBuffer(); } return objectBuffer; } public final void putArray(final byte[] array, int offset, int length, int flags) { paramOffset = encoder.putAddress(buffer, paramOffset, 0L); getObjectBuffer().putArray(paramIndex++, array, offset, length, flags); } public final void putArray(final short[] array, int offset, int length, int flags) { paramOffset = encoder.putAddress(buffer, paramOffset, 0L); getObjectBuffer().putArray(paramIndex++, array, offset, length, flags); } public final void putArray(final int[] array, int offset, int length, int flags) { paramOffset = encoder.putAddress(buffer, paramOffset, 0L); getObjectBuffer().putArray(paramIndex++, array, offset, length, flags); } public final void putArray(final long[] array, int offset, int length, int flags) { paramOffset = encoder.putAddress(buffer, paramOffset, 0L); getObjectBuffer().putArray(paramIndex++, array, offset, length, flags); } public final void putArray(final float[] array, int offset, int length, int flags) { paramOffset = encoder.putAddress(buffer, paramOffset, 0L); getObjectBuffer().putArray(paramIndex++, array, offset, length, flags); } public final void putArray(final double[] array, int offset, int length, int flags) { paramOffset = encoder.putAddress(buffer, paramOffset, 0L); getObjectBuffer().putArray(paramIndex++, array, offset, length, flags); } public final void putDirectBuffer(final java.nio.Buffer value, int offset, int length) { paramOffset = encoder.putAddress(buffer, paramOffset, 0L); getObjectBuffer().putDirectBuffer(paramIndex++, value, offset, length); } public final void putStruct(final byte[] struct, int offset) { final Type type = info.getParameterType(paramIndex); if (encoder.isRaw()) { paramOffset = FFI_ALIGN(paramOffset, type.alignment()); System.arraycopy(struct, offset, buffer, paramOffset, type.size()); paramOffset = FFI_ALIGN(paramOffset + type.size(), FFI_SIZEOF_ARG); } else { paramOffset = encoder.putAddress(buffer, paramOffset, 0L); getObjectBuffer().putArray(paramIndex, struct, offset, type.size(), ObjectBuffer.IN); } ++paramIndex; } public final void putStruct(final long struct) { final Type type = info.getParameterType(paramIndex); if (encoder.isRaw()) { paramOffset = FFI_ALIGN(paramOffset, type.alignment()); MemoryIO.getInstance().getByteArray(struct, buffer, paramOffset, type.size()); paramOffset = FFI_ALIGN(paramOffset + type.size(), FFI_SIZEOF_ARG); } else { paramOffset = encoder.putAddress(buffer, paramOffset, struct); } ++paramIndex; } public final void putJNIEnvironment() { paramOffset = encoder.putAddress(buffer, paramOffset, 0L); getObjectBuffer().putJNI(paramIndex++, ObjectBuffer.JNIENV); } private static final Encoder getEncoder() { if (Platform.getPlatform().getCPU() == Platform.CPU.I386) { return Foreign.getInstance().isRawParameterPackingEnabled() ? newI386RawEncoder() : newLE32Encoder(); } else if (Platform.getPlatform().addressSize() == 64) { return ByteOrder.nativeOrder().equals(ByteOrder.BIG_ENDIAN) ? newBE64Encoder() : newLE64Encoder(); } else { return ByteOrder.nativeOrder().equals(ByteOrder.BIG_ENDIAN) ? newBE32Encoder() : newLE32Encoder(); } } private static final Encoder newI386RawEncoder() { return new I386RawEncoder(); } private static final Encoder newLE32Encoder() { return new DefaultEncoder(LE32ArrayIO.INSTANCE); } private static final Encoder newLE64Encoder() { return new DefaultEncoder(LE64ArrayIO.INSTANCE); } private static final Encoder newBE32Encoder() { return new DefaultEncoder(BE32ArrayIO.INSTANCE); } private static final Encoder newBE64Encoder() { return new DefaultEncoder(BE64ArrayIO.INSTANCE); } /** * Encodes java data types into native parameter frames */ private static abstract class Encoder { /** Returns true if this Encoder is a raw encoder */ public abstract boolean isRaw(); /** Gets the size in bytes of the buffer required for the function */ public abstract int getBufferSize(CallInfo info); /** * Encodes a byte value into the byte array. * * @param buffer The destination byte buffer to place the encoded value. * @param offset The offset within the destination buffer to place the value. * @param value The value to encode. * @return The number of bytes consumed in encoding the value. */ public abstract int putByte(byte[] buffer, int offset, int value); /** * Encodes a short value into the byte array. * * @param buffer The destination byte buffer to place the encoded value. * @param offset The offset within the destination buffer to place the value. * @param value The value to encode. * @return The number of bytes consumed in encoding the value. */ public abstract int putShort(byte[] buffer, int offset, int value); /** * Encodes an int value into the byte array. * * @param buffer The destination byte buffer to place the encoded value. * @param offset The offset within the destination buffer to place the value. * @param value The value to encode. * @return The number of bytes consumed in encoding the value. */ public abstract int putInt(byte[] buffer, int offset, int value); /** * Encodes a long value into the byte array. * * @param buffer The destination byte buffer to place the encoded value. * @param offset The offset within the destination buffer to place the value. * @param value The value to encode. * @return The number of bytes consumed in encoding the value. */ public abstract int putLong(byte[] buffer, int offset, long value); /** * Encodes a float value into the byte array. * * @param buffer The destination byte buffer to place the encoded value. * @param offset The offset within the destination buffer to place the value. * @param value The value to encode. * @return The number of bytes consumed in encoding the value. */ public abstract int putFloat(byte[] buffer, int offset, float value); /** * Encodes a double value into the byte array. * * @param buffer The destination byte buffer to place the encoded value. * @param offset The offset within the destination buffer to place the value. * @param value The value to encode. * @return The number of bytes consumed in encoding the value. */ public abstract int putDouble(byte[] buffer, int offset, double value); /** * Encodes a native memory address value into the byte array. * * @param buffer The destination byte buffer to place the encoded value. * @param offset The offset within the destination buffer to place the value. * @param value The value to encode. * @return The number of bytes consumed in encoding the value. */ public abstract int putAddress(byte[] buffer, int offset, long value); } /** * Packs arguments into a byte array in the format compliant with the * i386 sysv ABI, so the buffer can be copied directly onto the stack and * used. */ private static final class I386RawEncoder extends Encoder { private static final ArrayIO IO = LE32ArrayIO.INSTANCE; public final boolean isRaw() { return true; } public final int getBufferSize(CallInfo info) { return info.getRawParameterSize(); } public final int putByte(byte[] buffer, int offset, int value) { IO.putByte(buffer, offset, value); return offset + 4; } public final int putShort(byte[] buffer, int offset, int value) { IO.putShort(buffer, offset, value); return offset + 4; } public final int putInt(byte[] buffer, int offset, int value) { IO.putInt(buffer, offset, value); return offset + 4; } public final int putLong(byte[] buffer, int offset, long value) { IO.putLong(buffer, offset, value); return offset + 8; } public final int putFloat(byte[] buffer, int offset, float value) { IO.putFloat(buffer, offset, value); return offset + 4; } public final int putDouble(byte[] buffer, int offset, double value) { IO.putDouble(buffer, offset, value); return offset + 8; } public final int putAddress(byte[] buffer, int offset, long value) { IO.putAddress(buffer, offset, value); return offset + 4; } } private static final class DefaultEncoder extends Encoder { private final ArrayIO io; public DefaultEncoder(ArrayIO io) { this.io = io; } public final boolean isRaw() { return false; } public final int getBufferSize(CallInfo info) { return info.getParameterCount() * PARAM_SIZE; } public final int putByte(byte[] buffer, int offset, int value) { io.putByte(buffer, offset, value); return offset + PARAM_SIZE; } public final int putShort(byte[] buffer, int offset, int value) { io.putShort(buffer, offset, value); return offset + PARAM_SIZE; } public final int putInt(byte[] buffer, int offset, int value) { io.putInt(buffer, offset, value); return offset + PARAM_SIZE; } public final int putLong(byte[] buffer, int offset, long value) { io.putLong(buffer, offset, value); return offset + PARAM_SIZE; } public final int putFloat(byte[] buffer, int offset, float value) { io.putFloat(buffer, offset, value); return offset + PARAM_SIZE; } public final int putDouble(byte[] buffer, int offset, double value) { io.putDouble(buffer, offset, value); return offset + PARAM_SIZE; } public final int putAddress(byte[] buffer, int offset, long value) { io.putAddress(buffer, offset, value); return offset + PARAM_SIZE; } } private static abstract class ArrayIO { public abstract void putByte(byte[] buffer, int offset, int value); public abstract void putShort(byte[] buffer, int offset, int value); public abstract void putInt(byte[] buffer, int offset, int value); public abstract void putLong(byte[] buffer, int offset, long value); public final void putFloat(byte[] buffer, int offset, float value) { putInt(buffer, offset, Float.floatToRawIntBits(value)); } public final void putDouble(byte[] buffer, int offset, double value) { putLong(buffer, offset, Double.doubleToRawLongBits(value)); } public abstract void putAddress(byte[] buffer, int offset, long value); } /** * Base class for all little-endian architecture array encoders. */ private static abstract class LittleEndianArrayIO extends ArrayIO { public final void putByte(byte[] buffer, int offset, int value) { buffer[offset] = (byte) value; } public final void putShort(byte[] buffer, int offset, int value) { buffer[offset] = (byte) value; buffer[offset + 1] = (byte) (value >> 8); } public final void putInt(byte[] buffer, int offset, int value) { buffer[offset] = (byte) value; buffer[offset + 1] = (byte) (value >> 8); buffer[offset + 2] = (byte) (value >> 16); buffer[offset + 3] = (byte) (value >> 24); } public final void putLong(byte[] buffer, int offset, long value) { buffer[offset] = (byte) value; buffer[offset + 1] = (byte) (value >> 8); buffer[offset + 2] = (byte) (value >> 16); buffer[offset + 3] = (byte) (value >> 24); buffer[offset + 4] = (byte) (value >> 32); buffer[offset + 5] = (byte) (value >> 40); buffer[offset + 6] = (byte) (value >> 48); buffer[offset + 7] = (byte) (value >> 56); } } /** * Little endian, 32 bit implementation of ArrayIO */ private static final class LE32ArrayIO extends LittleEndianArrayIO { static final ArrayIO INSTANCE = new LE32ArrayIO(); public final void putAddress(byte[] buffer, int offset, long value) { buffer[offset] = (byte) value; buffer[offset + 1] = (byte) (value >> 8); buffer[offset + 2] = (byte) (value >> 16); buffer[offset + 3] = (byte) (value >> 24); } } /** * Little endian, 64 bit implementation of ArrayIO */ private static final class LE64ArrayIO extends LittleEndianArrayIO { static final ArrayIO INSTANCE = new LE64ArrayIO(); public final void putAddress(byte[] buffer, int offset, long value) { putLong(buffer, offset, value); } } /** * Base class for all big-endian architecture array encoders. */ private static abstract class BigEndianArrayIO extends ArrayIO { public final void putByte(byte[] buffer, int offset, int value) { buffer[offset] = (byte) value; } public final void putShort(byte[] buffer, int offset, int value) { buffer[offset + 0] = (byte) (value >> 8); buffer[offset + 1] = (byte) value; } public final void putInt(byte[] buffer, int offset, int value) { buffer[offset + 0] = (byte) (value >> 24); buffer[offset + 1] = (byte) (value >> 16); buffer[offset + 2] = (byte) (value >> 8); buffer[offset + 3] = (byte) value; } public final void putLong(byte[] buffer, int offset, long value) { buffer[offset + 0] = (byte) (value >> 56); buffer[offset + 1] = (byte) (value >> 48); buffer[offset + 2] = (byte) (value >> 40); buffer[offset + 3] = (byte) (value >> 32); buffer[offset + 4] = (byte) (value >> 24); buffer[offset + 5] = (byte) (value >> 16); buffer[offset + 6] = (byte) (value >> 8); buffer[offset + 7] = (byte) value; } } /** * Big endian, 32 bit array encoder */ private static final class BE32ArrayIO extends BigEndianArrayIO { static final ArrayIO INSTANCE = new BE32ArrayIO(); public void putAddress(byte[] buffer, int offset, long value) { buffer[offset + 0] = (byte) (value >> 24); buffer[offset + 1] = (byte) (value >> 16); buffer[offset + 2] = (byte) (value >> 8); buffer[offset + 3] = (byte) value; } } /** * Big endian, 64 bit array encoder */ private static final class BE64ArrayIO extends BigEndianArrayIO { static final ArrayIO INSTANCE = new BE64ArrayIO(); public void putAddress(byte[] buffer, int offset, long value) { putLong(buffer, offset, value); } } /** * Aligns an address to a boundary * * @param v The address to roundup * @param a The boundary to align to. * @return The aligned address. */ private static final int FFI_ALIGN(int v, int a) { return ((v - 1) | (a - 1)) + 1; } } jffi-1.0.2/src/com/kenai/jffi/InvocationBuffer.java0000644000175000017500000001257311424636215022062 0ustar twernertwerner/* * Copyright (C) 2007-2009 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ package com.kenai.jffi; import java.nio.Buffer; /** * A parameter buffer used when invoking a function */ public interface InvocationBuffer { /** * Adds an 8 bit integer parameter. * * @param value An 8 bit integer value to use as the parameter. */ public abstract void putByte(final int value); /** * Adds a 16 bit integer parameter. * * @param value A 16 bit integer value to use as the parameter. */ public abstract void putShort(final int value); /** * Adds a 32 bit integer parameter. * * @param value A 32 bit integer value to use as the parameter. */ public abstract void putInt(final int value); /** * Adds a 64 bit integer parameter. * * @param value A 64 bit integer value to use as the parameter. */ public abstract void putLong(final long value); /** * Adds a 32 bit floating point parameter. * * @param value A 32 bit floating point value to use as the parameter. */ public abstract void putFloat(final float value); /** * Adds a 64 bit floating point parameter. * * @param value A 64 bit floating point value to use as the parameter. */ public abstract void putDouble(final double value); /** * Adds a native address parameter. * * @param value A native address value to use as the parameter. */ public abstract void putAddress(final long value); /** * Adds a java byte array as a pointer parameter. * * @param value The java array to use as the pointer parameter. * @param offset The offset from the start of the array. * @param length The length of the array to use. * @param flags The flags to use (IN, OUT) */ public abstract void putArray(final byte[] value, int offset, int length, int flags); /** * Adds a java short array as a pointer parameter. * * @param value The java array to use as the pointer parameter. * @param offset The offset from the start of the array. * @param length The length of the array to use. * @param flags The flags to use (IN, OUT) */ public abstract void putArray(final short[] value, int offset, int length, int flags); /** * Adds a java int array as a pointer parameter. * * @param value The java array to use as the pointer parameter. * @param offset The offset from the start of the array. * @param length The length of the array to use. * @param flags The flags to use (IN, OUT) */ public abstract void putArray(final int[] value, int offset, int length, int flags); /** * Adds a java long array as a pointer parameter. * * @param value The java array to use as the pointer parameter. * @param offset The offset from the start of the array. * @param length The length of the array to use. * @param flags The flags to use (IN, OUT) */ public abstract void putArray(final long[] value, int offset, int length, int flags); /** * Adds a java float array as a pointer parameter. * * @param value The java array to use as the pointer parameter. * @param offset The offset from the start of the array. * @param length The length of the array to use. * @param flags The flags to use (IN, OUT) */ public abstract void putArray(final float[] value, int offset, int length, int flags); /** * Adds a java double array as a pointer parameter. * * @param value The java array to use as the pointer parameter. * @param offset The offset from the start of the array. * @param length The length of the array to use. * @param flags The flags to use (IN, OUT) */ public abstract void putArray(final double[] value, int offset, int length, int flags); /** * Adds a java direct buffer as a pointer parameter. * @param buffer The buffer to use as a pointer argument. * @param offset An offset to add to the buffer native address. * @param length The length of the buffer to use. */ public abstract void putDirectBuffer(final Buffer buffer, int offset, int length); /** * Adds a struct or union as a parameter. * * This passes the struct or union by value, not by reference. * * @param struct A java byte array with the struct contents. * @param offset The offset from the start of the array. */ public void putStruct(final byte[] struct, int offset); /** * Adds a struct or union as a parameter. * * This passes the struct or union by value, not by reference. * * @param struct The native address to use as the struct contents. */ public void putStruct(final long struct); } jffi-1.0.2/src/com/kenai/jffi/DirectClosureBuffer.java0000644000175000017500000001220611424636215022511 0ustar twernertwerner/* * Copyright (C) 2008, 2009 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ package com.kenai.jffi; /** * Implementation of the {@link Closure.Buffer} interface to read/write * parameter and return value data in native memory */ final class DirectClosureBuffer implements Closure.Buffer { private static final MemoryIO IO = MemoryIO.getInstance(); private static final NativeWordIO WordIO = NativeWordIO.getInstance(); private static final long PARAM_SIZE = Platform.getPlatform().addressSize() / 8; private final long retval; private final long parameters; /* Keep references to the return and parameter types to prevent garbage collection */ private final CallContext callContext; public DirectClosureBuffer(CallContext callContext, long retval, long parameters) { super(); this.callContext = callContext; this.retval = retval; this.parameters = parameters; } public final byte getByte(int index) { return IO.getByte(IO.getAddress(parameters + (index * PARAM_SIZE))); } public final short getShort(int index) { return IO.getShort(IO.getAddress(parameters + (index * PARAM_SIZE))); } public final int getInt(int index) { return IO.getInt(IO.getAddress(parameters + (index * PARAM_SIZE))); } public final long getLong(int index) { return IO.getLong(IO.getAddress(parameters + (index * PARAM_SIZE))); } public final float getFloat(int index) { return IO.getFloat(IO.getAddress(parameters + (index * PARAM_SIZE))); } public final double getDouble(int index) { return IO.getDouble(IO.getAddress(parameters + (index * PARAM_SIZE))); } public final long getAddress(int index) { return IO.getAddress(IO.getAddress(parameters + (index * PARAM_SIZE))); } public final long getStruct(int index) { return IO.getAddress(parameters + (index * PARAM_SIZE)); } public final void setByteReturn(byte value) { WordIO.put(retval, value); } public final void setShortReturn(short value) { WordIO.put(retval, value); } public final void setIntReturn(int value) { WordIO.put(retval, value); } public final void setLongReturn(long value) { IO.putLong(retval, value); } public final void setFloatReturn(float value) { IO.putFloat(retval, value); } public final void setDoubleReturn(double value) { IO.putDouble(retval, value); } public final void setAddressReturn(long address) { IO.putAddress(retval, address); } public void setStructReturn(long value) { IO.copyMemory(value, retval, callContext.getReturnType().size()); } public void setStructReturn(byte[] data, int offset) { IO.putByteArray(retval, data, offset, callContext.getReturnType().size()); } /** * Reads annd writes data types that are smaller than the size of a native * long, as a native long for compatibility with FFI. */ private static abstract class NativeWordIO { public static final NativeWordIO getInstance() { return Platform.getPlatform().addressSize() == 32 ? NativeWordIO32.INSTANCE : NativeWordIO64.INSTANCE; } /** * Writes a native long argument to native memory. * * @param address The address to write the value at * @param value The value to write. */ abstract void put(long address, int value); /** * Reads a native long argument from native memory. * @param address The memory address to read the value from * @return An integer */ abstract int get(long address); } private static final class NativeWordIO32 extends NativeWordIO { private static final com.kenai.jffi.MemoryIO IO = com.kenai.jffi.MemoryIO.getInstance(); static final NativeWordIO INSTANCE = new NativeWordIO32(); void put(long address, int value) { IO.putInt(address, value); } int get(long address) { return IO.getInt(address); } } private static final class NativeWordIO64 extends NativeWordIO { private static final com.kenai.jffi.MemoryIO IO = com.kenai.jffi.MemoryIO.getInstance(); static final NativeWordIO INSTANCE = new NativeWordIO64(); void put(long address, int value) { IO.putLong(address, value); } int get(long address) { return (int) IO.getLong(address); } } } jffi-1.0.2/src/com/kenai/jffi/NativeMethod.java0000644000175000017500000000405611424636215021203 0ustar twernertwerner/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ package com.kenai.jffi; /** * Represents a native implementation of a method for a class */ public final class NativeMethod { final long function; final long name; final long signature; /** * Creates a new native method wrapper. * * @param address The address of the native method. * @param name The name of the java method. * @param signature The java signature. */ public NativeMethod(long address, String name, String signature) { this.function = address; this.name = nativeString(name); this.signature = nativeString(signature); } private static final long nativeString(String s) { byte[] bytes = s.getBytes(); long memory = MemoryIO.getInstance().allocateMemory(bytes.length + 1, false); if (memory == 0L) { throw new OutOfMemoryError("failed to allocate memory for string"); } MemoryIO.getInstance().putZeroTerminatedByteArray(memory, bytes, 0, bytes.length); return memory; } @Override protected void finalize() throws Throwable { try { if (name != 0L) { MemoryIO.getInstance().freeMemory(name); } if (signature != 0L) { MemoryIO.getInstance().freeMemory(signature); } } finally { super.finalize(); } } } jffi-1.0.2/src/com/kenai/jffi/NativeMethods.java0000644000175000017500000000742211424636215021366 0ustar twernertwerner/* * Copyright (C) 2009 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ package com.kenai.jffi; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.WeakHashMap; /** * Utility class to register native methods on a class */ public final class NativeMethods { /** * Store a link from the class to the native method holder in a weak * hash map, so as long as the class remains alive, the native memory for the * structures remains alive. * * This doesn't seem to be neccessary on sun's jvm, but best do it to be safe. */ private static final Map registeredMethods = new WeakHashMap(); private final long memory; private final List methods; private NativeMethods(long memory, List methods) { this.memory = memory; this.methods = new ArrayList(methods); } /** * Registers the native methods for a class. * * @param clazz The java class to register the native methods for. * @param methods The list of methods to attach to the class. */ public static synchronized final void register(Class clazz, List methods) { final long ptrSize = Platform.getPlatform().addressSize() / 8; final MemoryIO mm = MemoryIO.getInstance(); // // Each JNINativeMethod struct is 3 pointers // i.e. // typedef struct { // char *name; // char *signature; // void *fnPtr; // } JNINativeMethod; long memory = mm.allocateMemory(methods.size() * 3 * ptrSize, true); if (memory == 0L) { throw new OutOfMemoryError("could not allocate native memory"); } NativeMethods nm = new NativeMethods(memory, methods); long off = 0; for (NativeMethod m : methods) { mm.putAddress(memory + off, m.name); off += ptrSize; mm.putAddress(memory + off, m.signature); off += ptrSize; mm.putAddress(memory + off, m.function); off += ptrSize; } if (Foreign.getInstance().registerNatives(clazz, memory, methods.size()) != Foreign.JNI_OK) { throw new RuntimeException("failed to register native methods"); } registeredMethods.put(clazz, nm); } /** * Removes all native method attachments for the specified class. * * @param clazz The class to unregister the native methods on. */ public static synchronized final void unregister(Class clazz) { if (!registeredMethods.containsKey(clazz)) { throw new IllegalArgumentException("methods were not registered on class via NativeMethods.register"); } if (Foreign.getInstance().unregisterNatives(clazz) != Foreign.JNI_OK) { throw new RuntimeException("failed to unregister native methods"); } registeredMethods.remove(clazz); } @Override protected void finalize() throws Throwable { try { MemoryIO.getInstance().freeMemory(memory); } finally { super.finalize(); } } } jffi-1.0.2/jni/0000755000175000017500000000000011424636215013152 5ustar twernertwernerjffi-1.0.2/jni/jffi/0000755000175000017500000000000011424636215014070 5ustar twernertwernerjffi-1.0.2/jni/jffi/Memory.c0000644000175000017500000000713211424636215015507 0ustar twernertwerner#include #include #ifndef _WIN32 # include #else # include # include # include #endif #include #include "Exception.h" #include "LastError.h" #include "com_kenai_jffi_Foreign.h" #include "jffi.h" /* * Class: com_kenai_jffi_Foreign * Method: pageSize * Signature: ()J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_pageSize(JNIEnv *env, jobject self) { #ifndef _WIN32 return sysconf(_SC_PAGESIZE); #else SYSTEM_INFO si; GetSystemInfo(&si); return si.dwPageSize; #endif } #ifndef _WIN32 static int PROT(int p); static int FLAGS(int f); /* * Class: com_kenai_jffi_Foreign * Method: mmap * Signature: (JJIIIJ)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_mmap(JNIEnv *env, jobject self, jlong addr, jlong len, jint prot, jint flags, jint fd, jlong off) { caddr_t result; result = mmap(j2p(addr), len, PROT(prot), FLAGS(flags), fd, off); if (unlikely(result == (caddr_t) -1)) { jffi_save_errno(); return -1; } return p2j(result); } /* * Class: com_kenai_jffi_Foreign * Method: munmap * Signature: (JJ)I */ JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_munmap(JNIEnv *env, jobject self, jlong addr, jlong len) { int result = munmap(j2p(addr), len); if (unlikely(result != 0)) { jffi_save_errno(); return -1; } return 0; } /* * Class: com_kenai_jffi_Foreign * Method: mprotect * Signature: (JJI)I */ JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_mprotect(JNIEnv *env, jobject self, jlong addr, jlong len, jint prot) { int result = mprotect(j2p(addr), len, PROT(prot)); if (unlikely(result != 0)) { jffi_save_errno(); return -1; } return 0; } static int PROT(int p) { int n = 0; n |= ((p & com_kenai_jffi_Foreign_PROT_NONE) != 0) ? PROT_NONE : 0; n |= ((p & com_kenai_jffi_Foreign_PROT_READ) != 0) ? PROT_READ : 0; n |= ((p & com_kenai_jffi_Foreign_PROT_WRITE) != 0) ? PROT_WRITE : 0; n |= ((p & com_kenai_jffi_Foreign_PROT_EXEC) != 0) ? PROT_EXEC : 0; return n; } static int FLAGS(int j) { int m = 0; #define M(x) m |= ((j & com_kenai_jffi_Foreign_MAP_##x) != 0) ? MAP_##x : 0 M(FIXED); M(SHARED); M(PRIVATE); #ifdef MAP_NORESERVE M(NORESERVE); #endif M(ANON); #ifdef MAP_ALIGN M(ALIGN); #endif #ifdef MAP_TEXT M(TEXT); #endif return m; } #else /* _WIN32 */ /* * Class: com_kenai_jffi_Foreign * Method: VirtualAlloc * Signature: (JIII)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_VirtualAlloc(JNIEnv *env, jobject self, jlong addr, jint size, jint flags, jint prot) { void* ptr = VirtualAlloc(j2p(addr), size, flags, prot); if (unlikely(ptr == NULL)) { jffi_save_errno(); return 0; } return p2j(ptr); } /* * Class: com_kenai_jffi_Foreign * Method: VirtualFree * Signature: (JI)Z */ JNIEXPORT jboolean JNICALL Java_com_kenai_jffi_Foreign_VirtualFree(JNIEnv *env, jobject self, jlong addr, jint size, jint flags) { if (!VirtualFree(j2p(addr), size, flags)) { jffi_save_errno(); return JNI_FALSE; } return JNI_TRUE; } /* * Class: com_kenai_jffi_Foreign * Method: VirtualProtect * Signature: (JII)Z */ JNIEXPORT jboolean JNICALL Java_com_kenai_jffi_Foreign_VirtualProtect(JNIEnv *env, jobject self, jlong addr, jint size, jint prot) { DWORD oldprot; if (!VirtualProtect(j2p(addr), size, prot, &oldprot)) { jffi_save_errno(); return JNI_FALSE; } return JNI_TRUE; } #endif /* !_WIN32 */ jffi-1.0.2/jni/jffi/Invoke.c0000644000175000017500000004127211424636215015475 0ustar twernertwerner#include #include #if defined (__sun) || defined(_AIX) # include #endif #ifdef _WIN32 # include #endif #include #include #include #include "jffi.h" #include "Exception.h" #include "Function.h" #include "Array.h" #include "LastError.h" #include "com_kenai_jffi_Foreign.h" #define PARAM_SIZE (8) #define MAX_STACK_ARRAY (1024) #ifdef USE_RAW static void invokeArray(JNIEnv* env, jlong ctxAddress, jbyteArray paramBuffer, void* returnBuffer) { Function* ctx = (Function *) j2p(ctxAddress); FFIValue tmpValue; jbyte *tmpBuffer = (jbyte *) &tmpValue; if (likely(ctx->cif.nargs > 0)) { tmpBuffer = alloca(ctx->cif.bytes); (*env)->GetByteArrayRegion(env, paramBuffer, 0, ctx->rawParameterSize, tmpBuffer); } ffi_raw_call(&ctx->cif, FFI_FN(ctx->function), returnBuffer, (ffi_raw *) tmpBuffer); SAVE_ERRNO(ctx); } #else static void invokeArray(JNIEnv* env, jlong ctxAddress, jbyteArray paramBuffer, void* returnBuffer) { Function* ctx = (Function *) j2p(ctxAddress); void** ffiArgs = { NULL }; jbyte *tmpBuffer = NULL; if (ctx->cif.nargs > 0) { unsigned int i; tmpBuffer = alloca(ctx->cif.nargs * PARAM_SIZE); ffiArgs = alloca(ctx->cif.nargs * sizeof(void *)); (*env)->GetByteArrayRegion(env, paramBuffer, 0, ctx->cif.nargs * PARAM_SIZE, tmpBuffer); for (i = 0; i < ctx->cif.nargs; ++i) { if (unlikely(ctx->cif.arg_types[i]->type == FFI_TYPE_STRUCT)) { ffiArgs[i] = *(void **) &tmpBuffer[i * PARAM_SIZE]; } else { ffiArgs[i] = &tmpBuffer[i * PARAM_SIZE]; } } } ffi_call(&ctx->cif, FFI_FN(ctx->function), returnBuffer, ffiArgs); SAVE_ERRNO(ctx); } #endif /* * Class: com_kenai_jffi_Foreign * Method: isRawParameterPackingEnabled * Signature: ()Z */ JNIEXPORT jboolean JNICALL Java_com_kenai_jffi_Foreign_isRawParameterPackingEnabled(JNIEnv* env, jobject self) { #ifdef USE_RAW return JNI_TRUE; #else return JNI_FALSE; #endif } /* * Class: com_kenai_jffi_Foreign * Method: invokeArrayInt32 * Signature: (J[B)I */ JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_invokeArrayReturnInt(JNIEnv* env, jclass self, jlong ctxAddress, jbyteArray paramBuffer) { FFIValue retval; invokeArray(env, ctxAddress, paramBuffer, &retval); return_int(retval); } /* * Class: com_kenai_jffi_Foreign * Method: invokeArrayInt64 * Signature: (J[B)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeArrayReturnLong(JNIEnv* env, jclass self, jlong ctxAddress, jbyteArray paramBuffer) { FFIValue retval; invokeArray(env, ctxAddress, paramBuffer, &retval); return retval.s64; } /* * Class: com_kenai_jffi_Foreign * Method: invokeArrayFloat * Signature: (J[B)F */ JNIEXPORT jfloat JNICALL Java_com_kenai_jffi_Foreign_invokeArrayReturnFloat(JNIEnv* env, jclass self, jlong ctxAddress, jbyteArray paramBuffer) { FFIValue retval; invokeArray(env, ctxAddress, paramBuffer, &retval); return retval.f; } /* * Class: com_kenai_jffi_Foreign * Method: invokeArrayDouble * Signature: (J[B)D */ JNIEXPORT jdouble JNICALL Java_com_kenai_jffi_Foreign_invokeArrayReturnDouble(JNIEnv* env, jclass self, jlong ctxAddress, jbyteArray paramBuffer) { FFIValue retval; invokeArray(env, ctxAddress, paramBuffer, &retval); return retval.d; } /* * Class: com_kenai_jffi_Foreign * Method: invokeArrayReturnStruct * Signature: (J[B[B)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_invokeArrayReturnStruct(JNIEnv* env, jclass self, jlong ctxAddress, jbyteArray paramBuffer, jbyteArray returnBuffer, jint offset) { Function* ctx = (Function *) j2p(ctxAddress); jbyte* retval = alloca(ctx->cif.rtype->size); jbyte* tmpBuffer; void** ffiArgs; int i; // // Due to the undocumented and somewhat strange struct-return handling when // using ffi_raw_call(), we convert from raw to ptr array, then call via normal // ffi_call // ffiArgs = alloca(ctx->cif.nargs * sizeof(void *)); #ifdef USE_RAW tmpBuffer = alloca(ctx->rawParameterSize); (*env)->GetByteArrayRegion(env, paramBuffer, 0, ctx->rawParameterSize, tmpBuffer); for (i = 0; i < (int) ctx->cif.nargs; ++i) { ffiArgs[i] = (tmpBuffer + ctx->rawParamOffsets[i]); } #else tmpBuffer = alloca(ctx->cif.nargs * PARAM_SIZE); (*env)->GetByteArrayRegion(env, paramBuffer, 0, ctx->cif.nargs * PARAM_SIZE, tmpBuffer); for (i = 0; i < (int) ctx->cif.nargs; ++i) { ffiArgs[i] = &tmpBuffer[i * PARAM_SIZE]; } #endif ffi_call(&ctx->cif, FFI_FN(ctx->function), retval, ffiArgs); SAVE_ERRNO(ctx); (*env)->SetByteArrayRegion(env, returnBuffer, offset, ctx->cif.rtype->size, retval); } #define MAX_STACK_OBJECTS (4) static void invokeArrayWithObjects_(JNIEnv* env, jlong ctxAddress, jbyteArray paramBuffer, jint objectCount, jint* infoBuffer, jobject* objectBuffer, void* retval) { Function* ctx = (Function *) j2p(ctxAddress); jbyte *tmpBuffer = NULL; void **ffiArgs = NULL; Array *arrays = NULL; unsigned int i, arrayCount = 0, paramBytes = 0; arrays = alloca(objectCount * sizeof(Array)); #if defined(USE_RAW) paramBytes = ctx->rawParameterSize; #else paramBytes = ctx->cif.nargs * PARAM_SIZE; #endif tmpBuffer = alloca(paramBytes); (*env)->GetByteArrayRegion(env, paramBuffer, 0, paramBytes, tmpBuffer); #ifndef USE_RAW ffiArgs = alloca(ctx->cif.nargs * sizeof(void *)); for (i = 0; i < (unsigned int) ctx->cif.nargs; ++i) { ffiArgs[i] = &tmpBuffer[i * PARAM_SIZE]; } #endif for (i = 0; i < (unsigned int) objectCount; ++i) { int type = infoBuffer[i * 3]; jsize offset = infoBuffer[(i * 3) + 1]; jsize length = infoBuffer[(i * 3) + 2]; jobject object = objectBuffer[i]; int idx = (type & com_kenai_jffi_ObjectBuffer_INDEX_MASK) >> com_kenai_jffi_ObjectBuffer_INDEX_SHIFT; void* ptr; switch (type & com_kenai_jffi_ObjectBuffer_TYPE_MASK & ~com_kenai_jffi_ObjectBuffer_PRIM_MASK) { case com_kenai_jffi_ObjectBuffer_ARRAY: if (unlikely(object == NULL)) { throwException(env, NullPointer, "null object for parameter %d", idx); goto cleanup; } else if (unlikely((type & com_kenai_jffi_ObjectBuffer_PINNED) != 0)) { ptr = jffi_getArrayCritical(env, object, offset, length, type, &arrays[arrayCount]); if (unlikely(ptr == NULL)) { goto cleanup; } } else if (true && likely(length < MAX_STACK_ARRAY)) { ptr = alloca(jffi_arraySize(length + 1, type)); if (unlikely(jffi_getArrayBuffer(env, object, offset, length, type, &arrays[arrayCount], ptr) == NULL)) { goto cleanup; } } else { ptr = jffi_getArrayHeap(env, object, offset, length, type, &arrays[arrayCount]); if (unlikely(ptr == NULL)) { goto cleanup; } } ++arrayCount; break; case com_kenai_jffi_ObjectBuffer_BUFFER: ptr = (*env)->GetDirectBufferAddress(env, object); if (unlikely(ptr == NULL)) { throwException(env, NullPointer, "Could not get direct Buffer address"); goto cleanup; } ptr = ((char *) ptr + offset); break; case com_kenai_jffi_ObjectBuffer_JNI: switch (type & com_kenai_jffi_ObjectBuffer_TYPE_MASK) { case com_kenai_jffi_ObjectBuffer_JNIENV: ptr = env; break; case com_kenai_jffi_ObjectBuffer_JNIOBJECT: ptr = (void *) object; break; default: throwException(env, IllegalArgument, "Unsupported object type: %#x", type & com_kenai_jffi_ObjectBuffer_TYPE_MASK); goto cleanup; } break; default: throwException(env, IllegalArgument, "Unsupported object type: %#x", type & com_kenai_jffi_ObjectBuffer_TYPE_MASK); goto cleanup; } #if defined(USE_RAW) *((void **)(tmpBuffer + ctx->rawParamOffsets[idx])) = ptr; #else if (unlikely(ctx->cif.arg_types[idx]->type == FFI_TYPE_STRUCT)) { ffiArgs[idx] = ptr; } else { *((void **) ffiArgs[idx]) = ptr; } #endif } #if defined(USE_RAW) // // Special case for struct return values - unroll into a ptr array and // use ffi_call, since ffi_raw_call with struct return values is undocumented. // if (unlikely(ctx->cif.rtype->type == FFI_TYPE_STRUCT)) { ffiArgs = alloca(ctx->cif.nargs * sizeof(void *)); for (i = 0; i < ctx->cif.nargs; ++i) { ffiArgs[i] = (tmpBuffer + ctx->rawParamOffsets[i]); } ffi_call(&ctx->cif, FFI_FN(ctx->function), retval, ffiArgs); } else { ffi_raw_call(&ctx->cif, FFI_FN(ctx->function), retval, (ffi_raw *) tmpBuffer); } #else ffi_call(&ctx->cif, FFI_FN(ctx->function), retval, ffiArgs); #endif SAVE_ERRNO(ctx); cleanup: /* Release any array backing memory */ for (i = 0; i < arrayCount; ++i) { if (arrays[i].release != NULL) { //printf("releasing array=%p\n", arrays[i].elems); (*arrays[i].release)(env, &arrays[i]); } } } static void invokeArrayWithObjects(JNIEnv* env, jlong ctxAddress, jbyteArray paramBuffer, jint objectCount, jintArray objectInfo, jobjectArray objectArray, void* retval) { jint* infoBuffer = alloca(objectCount * sizeof(jint) * 3); jobject* objectBuffer = alloca(objectCount * sizeof(jobject)); int i; (*env)->GetIntArrayRegion(env, objectInfo, 0, objectCount * 3, infoBuffer); for (i = 0; i < objectCount; ++i) { objectBuffer[i] = (*env)->GetObjectArrayElement(env, objectArray, i); } invokeArrayWithObjects_(env, ctxAddress, paramBuffer, objectCount, infoBuffer, objectBuffer, retval); } /* * Class: com_kenai_jffi_Foreign * Method: invokeArrayWithObjectsInt32 * Signature: (J[B[I[Ljava/lang/Object;)I */ JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_invokeArrayWithObjectsInt32(JNIEnv* env, jobject self, jlong ctxAddress, jbyteArray paramBuffer, jint objectCount, jintArray objectInfo, jobjectArray objectArray) { FFIValue retval; invokeArrayWithObjects(env, ctxAddress, paramBuffer, objectCount, objectInfo, objectArray, &retval); return_int(retval); } /* * Class: com_kenai_jffi_Foreign * Method: invokeArrayO1Int32 * Signature: (J[BILjava/lang/Object;I)I */ JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_invokeArrayO1Int32(JNIEnv* env, jobject self, jlong ctxAddress, jbyteArray paramBuffer, jobject o1, jint o1info, jint o1off, jint o1len) { FFIValue retval; jint info[] = { o1info, o1off, o1len }; jobject objects[] = { o1 }; invokeArrayWithObjects_(env, ctxAddress, paramBuffer, 1, info, objects, &retval); return_int(retval); } /* * Class: com_kenai_jffi_Foreign * Method: invokeArrayO2Int32 * Signature: (J[BLjava/lang/Object;IIILjava/lang/Object;III)I */ JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_invokeArrayO2Int32(JNIEnv* env, jobject self, jlong ctxAddress, jbyteArray paramBuffer, jobject o1, jint o1info, jint o1off, jint o1len, jobject o2, jint o2info, jint o2off, jint o2len) { FFIValue retval; jint info[] = { o1info, o1off, o1len, o2info, o2off, o2len }; jobject objects[] = { o1, o2 }; invokeArrayWithObjects_(env, ctxAddress, paramBuffer, 2, info, objects, &retval); return_int(retval); } /* * Class: com_kenai_jffi_Foreign * Method: invokeArrayWithObjectsInt64 * Signature: (J[BI[I[Ljava/lang/Object;)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeArrayWithObjectsInt64(JNIEnv* env, jobject self, jlong ctxAddress, jbyteArray paramBuffer, jint objectCount, jintArray objectInfo, jobjectArray objectArray) { FFIValue retval; invokeArrayWithObjects(env, ctxAddress, paramBuffer, objectCount, objectInfo, objectArray, &retval); return retval.s64; } /* * Class: com_kenai_jffi_Foreign * Method: invokeArrayO1Int64 * Signature: (J[BLjava/lang/Object;III)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeArrayO1Int64(JNIEnv* env, jobject self, jlong ctxAddress, jbyteArray paramBuffer, jobject o1, jint o1info, jint o1off, jint o1len) { FFIValue retval; jint info[] = { o1info, o1off, o1len }; jobject objects[] = { o1 }; invokeArrayWithObjects_(env, ctxAddress, paramBuffer, 1, info, objects, &retval); return retval.j; } /* * Class: com_kenai_jffi_Foreign * Method: invokeArrayO2Int64 * Signature: (J[BLjava/lang/Object;IIILjava/lang/Object;III)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeArrayO2Int64(JNIEnv* env, jobject self, jlong ctxAddress, jbyteArray paramBuffer, jobject o1, jint o1info, jint o1off, jint o1len, jobject o2, jint o2info, jint o2off, jint o2len) { FFIValue retval; jint info[] = { o1info, o1off, o1len, o2info, o2off, o2len }; jobject objects[] = { o1, o2 }; invokeArrayWithObjects_(env, ctxAddress, paramBuffer, 2, info, objects, &retval); return retval.j; } /* * Class: com_kenai_jffi_Foreign * Method: invokeArrayWithObjectsFloat * Signature: (J[BI[I[Ljava/lang/Object;)F */ JNIEXPORT jfloat JNICALL Java_com_kenai_jffi_Foreign_invokeArrayWithObjectsFloat(JNIEnv* env, jobject self, jlong ctxAddress, jbyteArray paramBuffer, jint objectCount, jintArray objectInfo, jobjectArray objectArray) { FFIValue retval; invokeArrayWithObjects(env, ctxAddress, paramBuffer, objectCount, objectInfo, objectArray, &retval); return retval.f; } /* * Class: com_kenai_jffi_Foreign * Method: invokeArrayWithObjectsDouble * Signature: (J[BI[I[Ljava/lang/Object;)D */ JNIEXPORT jdouble JNICALL Java_com_kenai_jffi_Foreign_invokeArrayWithObjectsDouble(JNIEnv* env, jobject self, jlong ctxAddress, jbyteArray paramBuffer, jint objectCount, jintArray objectInfo, jobjectArray objectArray) { FFIValue retval; invokeArrayWithObjects(env, ctxAddress, paramBuffer, objectCount, objectInfo, objectArray, &retval); return retval.d; } /* * Class: com_kenai_jffi_Foreign * Method: invokeArrayWithObjectsReturnStruct * Signature: (J[BI[I[Ljava/lang/Object;[BI)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_invokeArrayWithObjectsReturnStruct(JNIEnv* env, jobject self, jlong ctxAddress, jbyteArray paramBuffer, jint objectCount, jintArray objectInfo, jobjectArray objectArray, jbyteArray returnBuffer, jint returnBufferOffset) { Function* ctx = (Function *) j2p(ctxAddress); jbyte* retval = alloca(ctx->cif.rtype->size); invokeArrayWithObjects(env, ctxAddress, paramBuffer, objectCount, objectInfo, objectArray, retval); (*env)->SetByteArrayRegion(env, returnBuffer, returnBufferOffset, ctx->cif.rtype->size, retval); } /* * Class: com_kenai_jffi_Foreign * Method: invokePointerParameterArray * Signature: (JJ[J)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_invokePointerParameterArray(JNIEnv *env, jobject self, jlong ctxAddress, jlong returnBuffer, jlongArray parameterArray) { Function* ctx = (Function *) j2p(ctxAddress); int parameterCount; jlong* params = NULL; void** ffiArgs = NULL; int i; if (unlikely(ctxAddress == 0LL)) { throwException(env, NullPointer, "context address is null"); return; } if (unlikely(returnBuffer == 0LL)) { throwException(env, NullPointer, "result buffer is null"); return; } if (unlikely(parameterArray == NULL)) { throwException(env, NullPointer, "parameter array is null"); return; } parameterCount = (*env)->GetArrayLength(env, parameterArray); if (parameterCount > 0) { params = alloca(parameterCount * sizeof(jlong)); ffiArgs = alloca(parameterCount * sizeof(void *)); (*env)->GetLongArrayRegion(env, parameterArray, 0, parameterCount, params); for (i = 0; i < parameterCount; ++i) { ffiArgs[i] = j2p(params[i]); } } ffi_call(&ctx->cif, FFI_FN(ctx->function), j2p(returnBuffer), ffiArgs); } jffi-1.0.2/jni/jffi/MemoryUtil.c0000644000175000017500000000367311424636215016353 0ustar twernertwerner/* * Copyright (C) 2007, 2008, 2009 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ #include #include #ifndef _WIN32 # include #endif #include #include #include #include #ifndef _WIN32 # include #else # include #endif #include #include "MemoryUtil.h" int jffi_getPageSize(void) { #ifdef _WIN32 SYSTEM_INFO si; GetSystemInfo(&si); return si.dwPageSize; #else return sysconf(_SC_PAGESIZE); #endif } void* jffi_allocatePages(int npages) { #ifdef _WIN32 return VirtualAlloc(NULL, npages * jffi_getPageSize(), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); #else caddr_t memory = mmap(NULL, npages * jffi_getPageSize(), PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); return (memory != (caddr_t) -1) ? memory : NULL; #endif } bool jffi_freePages(void *addr, int npages) { #ifdef _WIN32 return VirtualFree(addr, 0, MEM_RELEASE); #else return munmap(addr, npages * jffi_getPageSize()) == 0; #endif } bool jffi_makePagesExecutable(void* memory, int npages) { #ifdef _WIN32 DWORD oldProtect; return VirtualProtect(memory, npages * jffi_getPageSize(), PAGE_EXECUTE_READ, &oldProtect); #else return mprotect(memory, npages * jffi_getPageSize(), PROT_READ | PROT_EXEC) == 0; #endif } jffi-1.0.2/jni/jffi/MemoryIO.c0000644000175000017500000001525011424636215015737 0ustar twernertwerner/* * Copyright (C) 2007 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ #include #include #include #include #include #include #include #include "jffi.h" #include "com_kenai_jffi_Foreign.h" #define GET(JTYPE, NTYPE) JNIEXPORT NTYPE JNICALL \ Java_com_kenai_jffi_Foreign_get##JTYPE(JNIEnv* env, jobject self, jlong address) \ { NTYPE tmp; memcpy(&tmp, j2p(address), sizeof(tmp)); return tmp; } #define PUT(JTYPE, NTYPE) \ JNIEXPORT void JNICALL \ Java_com_kenai_jffi_Foreign_put##JTYPE(JNIEnv *env, jobject self, jlong address, NTYPE value) \ { memcpy(j2p(address), &value, sizeof(value)); } #define COPY(JTYPE, NTYPE) \ JNIEXPORT void JNICALL \ Java_com_kenai_jffi_Foreign_put##JTYPE##Array(JNIEnv* env, jobject unsafe, jlong address, jobject obj, jint offset, jint length) \ { \ (*env)->Get##JTYPE##ArrayRegion(env, obj, offset, length, (NTYPE *) j2p(address)); \ } \ JNIEXPORT void JNICALL \ Java_com_kenai_jffi_Foreign_get##JTYPE##Array(JNIEnv* env, jobject unsafe, jlong address, jobject obj, jint offset, jint length) \ { \ (*env)->Set##JTYPE##ArrayRegion(env, obj, offset, length, (NTYPE *) j2p(address)); \ } #define UNSAFE(J, N) GET(J, N) PUT(J, N) COPY(J, N) UNSAFE(Byte, jbyte); UNSAFE(Char, jchar); UNSAFE(Boolean, jboolean); UNSAFE(Short, jshort); UNSAFE(Int, jint); UNSAFE(Long, jlong); UNSAFE(Float, jfloat); UNSAFE(Double, jdouble); /* * Class: com_googlecode_jffi_JNIUnsafe * Method: getAddress * Signature: (J)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_getAddress(JNIEnv* ev, jobject self, jlong address) { void* tmp; memcpy(&tmp, j2p(address), sizeof(tmp)); return p2j(tmp); } /* * Class: com_googlecode_jffi_JNIUnsafe * Method: putAddress * Signature: (JJ)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_putAddress(JNIEnv* env, jobject self, jlong address, jlong value) { void* tmp = j2p(value); memcpy(j2p(address), &tmp, sizeof(tmp)); } /* * Class: com_googlecode_jffi_Unsafe_JNIUnsafe * Method: setMemory * Signature: (JJB)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_setMemory(JNIEnv* env, jobject self, jlong address, jlong size, jbyte value) { memset(j2p(address), value, size); } /* * Class: com_googlecode_jffi_lowlevel_Unsafe_JNIUnsafe * Method: copyMemory * Signature: (JJJ)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_copyMemory(JNIEnv* env, jobject self, jlong src, jlong dst, jlong size) { memcpy(j2p(dst), j2p(src), size); } /* * Class: com_googlecode_jffi_lowlevel_Unsafe * Method: memchr * Signature: (JIJ)I */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_memchr(JNIEnv* env, jobject self, jlong address, jint c, jlong maxlen) { return p2j(memchr(j2p(address), c, maxlen)); } /* * Class: com_kenai_jffi_Foreign * Method: memmove * Signature: (JJJ)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_memmove(JNIEnv* env, jobject self, jlong src, jlong dst, jlong size) { memmove(j2p(dst), j2p(src), size); } /* * Class: com_kenai_jffi_Foreign * Method: memcpy * Signature: (JJJ)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_memcpy(JNIEnv* env, jobject self, jlong src, jlong dst, jlong size) { memcpy(j2p(dst), j2p(src), size); } /* * Class: com_kenai_jffi_Foreign * Method: strlen * Signature: (J)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_strlen(JNIEnv* env, jobject self, jlong address) { return (jlong) strlen(j2p(address)); } /* * Class: com_kenai_jffi_Foreign * Method: getUTF8StringAsBytes * Signature: (J)[B */ JNIEXPORT jbyteArray JNICALL Java_com_kenai_jffi_Foreign_getZeroTerminatedByteArray__J(JNIEnv* env, jobject self, jlong address) { const char* str = (const char*) j2p(address); int len = strlen(str); jbyteArray bytes = (*env)->NewByteArray(env, len); (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte *) str); return bytes; } /* * Class: com_kenai_jffi_Foreign * Method: getZeroTerminatedByteArray * Signature: (JI)[B */ JNIEXPORT jbyteArray JNICALL Java_com_kenai_jffi_Foreign_getZeroTerminatedByteArray__JI(JNIEnv* env, jobject self, jlong address, jint maxlen) { const char *str = (const char*) j2p(address), *zp; jsize len = ((zp = memchr(str, 0, maxlen)) != NULL) ? zp - str : maxlen; jbyteArray bytes = (*env)->NewByteArray(env, len); (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte *) str); return bytes; } /* * Class: com_kenai_jffi_Foreign * Method: putZeroTerminatedByteArray * Signature: (J[BII)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_putZeroTerminatedByteArray(JNIEnv *env, jobject self, jlong address, jbyteArray data, jint offset, jint length) { (*env)->GetByteArrayRegion(env, data, offset, length, (jbyte *)j2p(address)); *((char *) (uintptr_t) address + length) = '\0'; } /* * Class: com_kenai_jffi_Foreign * Method: allocateMemory * Signature: (JZ)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_allocateMemory(JNIEnv* env, jobject self, jlong size, jboolean clear) { void* memory = malloc(size); if (memory != NULL && clear != JNI_FALSE) { memset(memory, 0, size); } return p2j(memory); } /* * Class: com_kenai_jffi_Foreign * Method: freeMemory * Signature: (J)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_freeMemory(JNIEnv* env, jobject self, jlong address) { free(j2p(address)); } /* * Class: com_kenai_jffi_Foreign * Method: newDirectByteBuffer * Signature: (I)Ljava/nio/ByteBuffer; */ JNIEXPORT jobject JNICALL Java_com_kenai_jffi_Foreign_newDirectByteBuffer(JNIEnv* env, jobject self, jlong address, jint capacity) { return (*env)->NewDirectByteBuffer(env, j2p(address), capacity); } /* * Class: com_kenai_jffi_Foreign * Method: getDirectBufferAddress * Signature: (Lcom/kenai/jffi/Closure/Buffer;)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_getDirectBufferAddress(JNIEnv* env, jobject self, jobject buffer) { return p2j((*env)->GetDirectBufferAddress(env, buffer)); } jffi-1.0.2/jni/jffi/Struct.c0000644000175000017500000001020411424636215015515 0ustar twernertwerner#include #include #include #if defined(__sun) || defined(_AIX) # include #endif #ifdef _WIN32 # include #endif #include #include #include "com_kenai_jffi_Foreign.h" #include "jffi.h" #include "Exception.h" #ifndef MAX # define MAX(x,y) ((x) > (y) ? (x) : (y)) #endif #define FFI_ALIGN(v, a) (((((size_t) (v))-1) | ((a)-1))+1) /* * Class: com_kenai_jffi_Foreign * Method: newStruct * Signature: ([J)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_newStruct(JNIEnv* env, jobject self, jlongArray typeArray, jboolean isUnion) { ffi_type* s = NULL; int fieldCount; jlong* fieldTypes; int i; if (typeArray == NULL) { throwException(env, NullPointer, "types array cannot be null"); return 0L; } fieldCount = (*env)->GetArrayLength(env, typeArray); if (fieldCount < 1) { throwException(env, IllegalArgument, "No fields specified"); return 0L; } s = calloc(1, sizeof(*s)); if (s == NULL) { throwException(env, OutOfMemory, "failed to allocate memory"); return 0L; } // // Need to terminate the list of field types with a NULL, so allocate 1 extra // s->elements = calloc(fieldCount + 1, sizeof(ffi_type *)); if (s->elements == NULL) { throwException(env, OutOfMemory, "failed to allocate memory"); goto error; } // Copy out all the field descriptors fieldTypes = alloca(fieldCount * sizeof(jlong)); (*env)->GetLongArrayRegion(env, typeArray, 0, fieldCount, fieldTypes); s->type = FFI_TYPE_STRUCT; s->size = 0; s->alignment = 0; for (i = 0; i < fieldCount; ++i) { ffi_type* elem = (ffi_type *) j2p(fieldTypes[i]); if (elem == NULL) { throwException(env, IllegalArgument, "type for field %d is NULL", i); goto error; } if (elem->size == 0) { throwException(env, IllegalArgument, "type for field %d has size 0", i); goto error; } s->elements[i] = elem; if (!isUnion) { s->size = FFI_ALIGN(s->size, elem->alignment) + elem->size; } else { s->size = MAX(s->size, elem->size); } s->alignment = MAX(s->alignment, elem->alignment); } if (s->size == 0) { throwException(env, Runtime, "struct size is zero"); goto error; } // Include tail padding s->size = FFI_ALIGN(s->size, s->alignment); return p2j(s); error: if (s != NULL) { if (s->elements != NULL) { free(s->elements); } free(s); } return 0L; } JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_newArray(JNIEnv* env, jobject self, jlong type, jint length) { ffi_type* elem = (ffi_type *) j2p(type); ffi_type* s = NULL; int i; if (elem == NULL) { throwException(env, NullPointer, "element type cannot be null"); return 0L; } if (elem->size == 0) { throwException(env, IllegalArgument, "element type size 0"); return 0L; } if (length < 1) { throwException(env, IllegalArgument, "array length == 0"); return 0L; } s = calloc(1, sizeof(*s)); if (s == NULL) { throwException(env, OutOfMemory, "failed to allocate memory"); return 0L; } s->type = FFI_TYPE_STRUCT; s->alignment = elem->alignment; s->size = length * elem->size; // Need to terminate the list of field types with a NULL, so allocate 1 extra s->elements = calloc(length + 1, sizeof(ffi_type *)); if (s->elements == NULL) { throwException(env, OutOfMemory, "failed to allocate memory"); free(s); return 0L; } for (i = 0; i < length; ++i) { s->elements[i] = elem; } return p2j(s); } /* * Class: com_kenai_jffi_Foreign * Method: freeStruct * Signature: (J)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_freeAggregate(JNIEnv* env, jobject self, jlong handle) { ffi_type* s = (ffi_type *) j2p(handle); if (s != NULL) { free(s->elements); free(s); } } jffi-1.0.2/jni/jffi/Array.h0000644000175000017500000000311211424636215015314 0ustar twernertwerner/* * Copyright (C) 2007, 2008 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ #ifndef jffi_Array_h #define jffi_Array_h // // WARNING! Do not change the layout of this struct, it may be used from assembler // typedef struct Array { void (*release)(JNIEnv *env, struct Array *); jobject array; void* elems; int offset; int length; } Array; extern void* jffi_getArrayBuffer(JNIEnv* env, jobject buf, jint offset, jint length, int type, struct Array* array, void* buffer); extern void* jffi_getArrayHeap(JNIEnv* env, jobject buf, jint offset, jint length, int type, struct Array* array); extern void* jffi_getArrayCritical(JNIEnv* env, jobject buf, jint offset, jint length, int type, struct Array* array); extern int jffi_arraySize(int length, int type); #include "com_kenai_jffi_ObjectBuffer.h" #define OBJ_INDEX_MASK com_kenai_jffi_ObjectBuffer_INDEX_MASK #define OBJ_INDEX_SHIFT com_kenai_jffi_ObjectBuffer_INDEX_SHIFT #endif /* jffi_Array_h */ jffi-1.0.2/jni/jffi/Array.c0000644000175000017500000001743411424636215015323 0ustar twernertwerner/* * Copyright (C) 2007, 2008 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ #include #include #include #include #include #include "jffi.h" #include "Exception.h" #include "com_kenai_jffi_ObjectBuffer.h" #include "Array.h" #define ARRAY_NULTERMINATE com_kenai_jffi_ObjectBuffer_ZERO_TERMINATE #define ARRAY_IN com_kenai_jffi_ObjectBuffer_IN #define ARRAY_OUT com_kenai_jffi_ObjectBuffer_OUT #define ARRAY_PINNED com_kenai_jffi_ObjectBuffer_PINNED #define ARRAY_CLEAR com_kenai_jffi_ObjectBuffer_CLEAR #define ARGPRIM_MASK com_kenai_jffi_ObjectBuffer_PRIM_MASK #define ARGTYPE_MASK com_kenai_jffi_ObjectBuffer_TYPE_MASK #define ARGTYPE_SHIFT com_kenai_jffi_ObjectBuffer_TYPE_SHIFT #define ARGFLAGS_MASK com_kenai_jffi_ObjectBuffer_FLAGS_MASK #define RELEASE(JTYPE, NTYPE) \ static void release##JTYPE##ArrayHeap(JNIEnv *env, Array *array) \ { \ (*env)->Set##JTYPE##ArrayRegion(env, array->array, array->offset, array->length, \ (NTYPE *) array->elems); \ free(array->elems); \ } \ static void free##JTYPE##Array(JNIEnv *env, Array *array) \ { \ free(array->elems); \ } \ static void release##JTYPE##ArrayBuffer(JNIEnv *env, Array *array) \ { \ (*env)->Set##JTYPE##ArrayRegion(env, array->array, array->offset, array->length, \ (NTYPE *) array->elems); \ } RELEASE(Byte, jbyte); RELEASE(Short, jshort); RELEASE(Int, jint); RELEASE(Long, jlong); RELEASE(Float, jfloat); RELEASE(Double, jdouble); #define isOut(flags) (((flags) & (ARRAY_IN | ARRAY_OUT)) != ARRAY_IN) #define isIn(flags) (((flags) & (ARRAY_IN | ARRAY_OUT)) != ARRAY_OUT) #define COPY_DATA(JTYPE, NTYPE, flags, obj, offset, length, array) do { \ if (isIn(flags)) { \ (*env)->Get##JTYPE##ArrayRegion(env, obj, offset, length, (NTYPE *) array->elems); \ } else if (unlikely((flags & ARRAY_CLEAR) != 0)) { \ memset(array->elems, 0, length * sizeof(NTYPE)); \ } \ } while (0) #define GET_ARRAY_BUFFER(JTYPE, NTYPE, flags, obj, offset, length, array) do { \ COPY_DATA(JTYPE, NTYPE, flags, obj, offset, length, array); \ (array)->release = isOut(flags) ? release##JTYPE##ArrayBuffer : NULL; \ } while (0) #define GET_ARRAY_HEAP(JTYPE, NTYPE, flags, obj, offset, length, array) do { \ int allocSize = sizeof(NTYPE) * (length + 1); \ (array)->elems = malloc(allocSize); \ if (unlikely((array)->elems == NULL)) { \ throwException(env, OutOfMemory, "failed to allocate native array of %d bytes", allocSize); \ return NULL; \ } \ COPY_DATA(JTYPE, NTYPE, flags, obj, offset, length, array); \ (array)->release = isOut(flags) ? release##JTYPE##ArrayHeap : free##JTYPE##Array; \ } while(0) void* jffi_getArrayHeap(JNIEnv* env, jobject buf, jsize offset, jsize length, int paramType, Array* array) { array->array = buf; array->offset = offset; array->length = length; /* * Byte arrays are used for struct backing in both jaffl and jruby ffi, so * are the most likely path. */ if (likely((paramType & ARGPRIM_MASK) == com_kenai_jffi_ObjectBuffer_BYTE)) { GET_ARRAY_HEAP(Byte, jbyte, paramType, buf, offset, length, array); // If the array was really a string, nul terminate it if ((paramType & (ARRAY_NULTERMINATE | ARRAY_IN | ARRAY_OUT)) != ARRAY_OUT) { *(((char *) array->elems) + length) = '\0'; } } else { switch (paramType & ARGPRIM_MASK) { case com_kenai_jffi_ObjectBuffer_SHORT: GET_ARRAY_HEAP(Short, jshort, paramType, buf, offset, length, array); break; case com_kenai_jffi_ObjectBuffer_INT: GET_ARRAY_HEAP(Int, jint, paramType, buf, offset, length, array); break; case com_kenai_jffi_ObjectBuffer_LONG: GET_ARRAY_HEAP(Long, jlong, paramType, buf, offset, length, array); break; case com_kenai_jffi_ObjectBuffer_FLOAT: GET_ARRAY_HEAP(Float, jfloat, paramType, buf, offset, length, array); break; case com_kenai_jffi_ObjectBuffer_DOUBLE: GET_ARRAY_HEAP(Double, jdouble, paramType, buf, offset, length, array); break; default: throwException(env, IllegalArgument, "Invalid array type: %#x\n", paramType); return NULL; } } return array->elems; } void* jffi_getArrayBuffer(JNIEnv* env, jobject buf, jint offset, jint length, int type, struct Array* array, void* buffer) { array->array = buf; array->elems = buffer; array->offset = offset; array->length = length; switch (type & ARGPRIM_MASK) { case com_kenai_jffi_ObjectBuffer_BYTE: GET_ARRAY_BUFFER(Byte, jbyte, type, buf, offset, length, array); // If the array was really a string, nul terminate it if ((type & (ARRAY_NULTERMINATE | ARRAY_IN | ARRAY_OUT)) != ARRAY_OUT) { *(((char *) array->elems) + length) = '\0'; } break; case com_kenai_jffi_ObjectBuffer_SHORT: GET_ARRAY_BUFFER(Short, jshort, type, buf, offset, length, array); break; case com_kenai_jffi_ObjectBuffer_INT: GET_ARRAY_BUFFER(Int, jint, type, buf, offset, length, array); break; case com_kenai_jffi_ObjectBuffer_LONG: GET_ARRAY_BUFFER(Long, jlong, type, buf, offset, length, array); break; case com_kenai_jffi_ObjectBuffer_FLOAT: GET_ARRAY_BUFFER(Float, jfloat, type, buf, offset, length, array); break; case com_kenai_jffi_ObjectBuffer_DOUBLE: GET_ARRAY_BUFFER(Double, jdouble, type, buf, offset, length, array); break; default: throwException(env, IllegalArgument, "Invalid array type: %#x\n", type); return NULL; } return array->elems; } int jffi_arraySize(int length, int type) { switch (type & ARGPRIM_MASK) { case com_kenai_jffi_ObjectBuffer_BYTE: return length * sizeof(jbyte); case com_kenai_jffi_ObjectBuffer_SHORT: return length * sizeof(jshort); case com_kenai_jffi_ObjectBuffer_INT: return length * sizeof(jint); case com_kenai_jffi_ObjectBuffer_LONG: return length * sizeof(jlong); case com_kenai_jffi_ObjectBuffer_FLOAT: return length * sizeof(jfloat); case com_kenai_jffi_ObjectBuffer_DOUBLE: return length * sizeof(jdouble); default: return 0; } } static void jffi_releaseCriticalArray(JNIEnv* env, Array *array) { (*env)->ReleasePrimitiveArrayCritical(env, array->array, array->elems, 0); } void* jffi_getArrayCritical(JNIEnv* env, jobject buf, jsize offset, jsize length, int paramType, struct Array* array) { array->array = buf; array->offset = offset; array->length = length; array->elems = (*env)->GetPrimitiveArrayCritical(env, array->array, NULL); if (unlikely(array->elems == NULL)) { throwException(env, NullPointer, "could not access array"); return NULL; } array->release = jffi_releaseCriticalArray; return (char *) array->elems + offset; } jffi-1.0.2/jni/jffi/MemoryUtil.h0000644000175000017500000000044311424636215016350 0ustar twernertwerner#ifndef JFFI_MEMORY_H #define JFFI_MEMORY_H #ifdef __cplusplus extern "C" { #endif int jffi_getPageSize(void); void* jffi_allocatePages(int npages); bool jffi_freePages(void *addr, int npages); bool jffi_makePagesExecutable(void* memory, int npages); #ifdef __cplusplus } #endif #endif jffi-1.0.2/jni/jffi/queue.h0000644000175000017500000004330711424636215015374 0ustar twernertwerner/* $OpenBSD: queue.h,v 1.32 2007/04/30 18:42:34 pedro Exp $ */ /* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ /* * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)queue.h 8.5 (Berkeley) 8/20/94 */ #ifndef _JFFI_QUEUE_H_ #define _JFFI_QUEUE_H_ /* * This file defines five types of data structures: singly-linked lists, * lists, simple queues, tail queues, and circular queues. * * * A singly-linked list is headed by a single forward pointer. The elements * are singly linked for minimum space and pointer manipulation overhead at * the expense of O(n) removal for arbitrary elements. New elements can be * added to the list after an existing element or at the head of the list. * Elements being removed from the head of the list should use the explicit * macro for this purpose for optimum efficiency. A singly-linked list may * only be traversed in the forward direction. Singly-linked lists are ideal * for applications with large datasets and few or no removals or for * implementing a LIFO queue. * * A list is headed by a single forward pointer (or an array of forward * pointers for a hash table header). The elements are doubly linked * so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before * or after an existing element or at the head of the list. A list * may only be traversed in the forward direction. * * A simple queue is headed by a pair of pointers, one the head of the * list and the other to the tail of the list. The elements are singly * linked to save space, so elements can only be removed from the * head of the list. New elements can be added to the list before or after * an existing element, at the head of the list, or at the end of the * list. A simple queue may only be traversed in the forward direction. * * A tail queue is headed by a pair of pointers, one to the head of the * list and the other to the tail of the list. The elements are doubly * linked so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before or * after an existing element, at the head of the list, or at the end of * the list. A tail queue may be traversed in either direction. * * A circle queue is headed by a pair of pointers, one to the head of the * list and the other to the tail of the list. The elements are doubly * linked so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before or after * an existing element, at the head of the list, or at the end of the list. * A circle queue may be traversed in either direction, but has a more * complex end of list detection. * * For details on the use of these macros, see the queue(3) manual page. */ #if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC)) #define _Q_INVALIDATE(a) (a) = ((void *)-1) #else #define _Q_INVALIDATE(a) #endif /* * Singly-linked List definitions. */ #define SLIST_HEAD(name, type) \ struct name { \ struct type *slh_first; /* first element */ \ } #define SLIST_HEAD_INITIALIZER(head) \ { NULL } #define SLIST_ENTRY(type) \ struct { \ struct type *sle_next; /* next element */ \ } /* * Singly-linked List access methods. */ #define SLIST_FIRST(head) ((head)->slh_first) #define SLIST_END(head) NULL #define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) #define SLIST_NEXT(elm, field) ((elm)->field.sle_next) #define SLIST_FOREACH(var, head, field) \ for((var) = SLIST_FIRST(head); \ (var) != SLIST_END(head); \ (var) = SLIST_NEXT(var, field)) #define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ for ((varp) = &SLIST_FIRST((head)); \ ((var) = *(varp)) != SLIST_END(head); \ (varp) = &SLIST_NEXT((var), field)) /* * Singly-linked List functions. */ #define SLIST_INIT(head) { \ SLIST_FIRST(head) = SLIST_END(head); \ } #define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ (elm)->field.sle_next = (slistelm)->field.sle_next; \ (slistelm)->field.sle_next = (elm); \ } while (0) #define SLIST_INSERT_HEAD(head, elm, field) do { \ (elm)->field.sle_next = (head)->slh_first; \ (head)->slh_first = (elm); \ } while (0) #define SLIST_REMOVE_NEXT(head, elm, field) do { \ (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \ } while (0) #define SLIST_REMOVE_HEAD(head, field) do { \ (head)->slh_first = (head)->slh_first->field.sle_next; \ } while (0) #define SLIST_REMOVE(head, elm, type, field) do { \ if ((head)->slh_first == (elm)) { \ SLIST_REMOVE_HEAD((head), field); \ } else { \ struct type *curelm = (head)->slh_first; \ \ while (curelm->field.sle_next != (elm)) \ curelm = curelm->field.sle_next; \ curelm->field.sle_next = \ curelm->field.sle_next->field.sle_next; \ _Q_INVALIDATE((elm)->field.sle_next); \ } \ } while (0) /* * List definitions. */ #define LIST_HEAD(name, type) \ struct name { \ struct type *lh_first; /* first element */ \ } #define LIST_HEAD_INITIALIZER(head) \ { NULL } #define LIST_ENTRY(type) \ struct { \ struct type *le_next; /* next element */ \ struct type **le_prev; /* address of previous next element */ \ } /* * List access methods */ #define LIST_FIRST(head) ((head)->lh_first) #define LIST_END(head) NULL #define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) #define LIST_NEXT(elm, field) ((elm)->field.le_next) #define LIST_FOREACH(var, head, field) \ for((var) = LIST_FIRST(head); \ (var)!= LIST_END(head); \ (var) = LIST_NEXT(var, field)) /* * List functions. */ #define LIST_INIT(head) do { \ LIST_FIRST(head) = LIST_END(head); \ } while (0) #define LIST_INSERT_AFTER(listelm, elm, field) do { \ if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ (listelm)->field.le_next->field.le_prev = \ &(elm)->field.le_next; \ (listelm)->field.le_next = (elm); \ (elm)->field.le_prev = &(listelm)->field.le_next; \ } while (0) #define LIST_INSERT_BEFORE(listelm, elm, field) do { \ (elm)->field.le_prev = (listelm)->field.le_prev; \ (elm)->field.le_next = (listelm); \ *(listelm)->field.le_prev = (elm); \ (listelm)->field.le_prev = &(elm)->field.le_next; \ } while (0) #define LIST_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.le_next = (head)->lh_first) != NULL) \ (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ (head)->lh_first = (elm); \ (elm)->field.le_prev = &(head)->lh_first; \ } while (0) #define LIST_REMOVE(elm, field) do { \ if ((elm)->field.le_next != NULL) \ (elm)->field.le_next->field.le_prev = \ (elm)->field.le_prev; \ *(elm)->field.le_prev = (elm)->field.le_next; \ _Q_INVALIDATE((elm)->field.le_prev); \ _Q_INVALIDATE((elm)->field.le_next); \ } while (0) #define LIST_REPLACE(elm, elm2, field) do { \ if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ (elm2)->field.le_next->field.le_prev = \ &(elm2)->field.le_next; \ (elm2)->field.le_prev = (elm)->field.le_prev; \ *(elm2)->field.le_prev = (elm2); \ _Q_INVALIDATE((elm)->field.le_prev); \ _Q_INVALIDATE((elm)->field.le_next); \ } while (0) /* * Simple queue definitions. */ #define SIMPLEQ_HEAD(name, type) \ struct name { \ struct type *sqh_first; /* first element */ \ struct type **sqh_last; /* addr of last next element */ \ } #define SIMPLEQ_HEAD_INITIALIZER(head) \ { NULL, &(head).sqh_first } #define SIMPLEQ_ENTRY(type) \ struct { \ struct type *sqe_next; /* next element */ \ } /* * Simple queue access methods. */ #define SIMPLEQ_FIRST(head) ((head)->sqh_first) #define SIMPLEQ_END(head) NULL #define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) #define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) #define SIMPLEQ_FOREACH(var, head, field) \ for((var) = SIMPLEQ_FIRST(head); \ (var) != SIMPLEQ_END(head); \ (var) = SIMPLEQ_NEXT(var, field)) /* * Simple queue functions. */ #define SIMPLEQ_INIT(head) do { \ (head)->sqh_first = NULL; \ (head)->sqh_last = &(head)->sqh_first; \ } while (0) #define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ (head)->sqh_last = &(elm)->field.sqe_next; \ (head)->sqh_first = (elm); \ } while (0) #define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.sqe_next = NULL; \ *(head)->sqh_last = (elm); \ (head)->sqh_last = &(elm)->field.sqe_next; \ } while (0) #define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ (head)->sqh_last = &(elm)->field.sqe_next; \ (listelm)->field.sqe_next = (elm); \ } while (0) #define SIMPLEQ_REMOVE_HEAD(head, field) do { \ if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ (head)->sqh_last = &(head)->sqh_first; \ } while (0) /* * Tail queue definitions. */ #define TAILQ_HEAD(name, type) \ struct name { \ struct type *tqh_first; /* first element */ \ struct type **tqh_last; /* addr of last next element */ \ } #define TAILQ_HEAD_INITIALIZER(head) \ { NULL, &(head).tqh_first } #define TAILQ_ENTRY(type) \ struct { \ struct type *tqe_next; /* next element */ \ struct type **tqe_prev; /* address of previous next element */ \ } /* * tail queue access methods */ #define TAILQ_FIRST(head) ((head)->tqh_first) #define TAILQ_END(head) NULL #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) #define TAILQ_LAST(head, headname) \ (*(((struct headname *)((head)->tqh_last))->tqh_last)) /* XXX */ #define TAILQ_PREV(elm, headname, field) \ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) #define TAILQ_EMPTY(head) \ (TAILQ_FIRST(head) == TAILQ_END(head)) #define TAILQ_FOREACH(var, head, field) \ for((var) = TAILQ_FIRST(head); \ (var) != TAILQ_END(head); \ (var) = TAILQ_NEXT(var, field)) #define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ for((var) = TAILQ_LAST(head, headname); \ (var) != TAILQ_END(head); \ (var) = TAILQ_PREV(var, headname, field)) /* * Tail queue functions. */ #define TAILQ_INIT(head) do { \ (head)->tqh_first = NULL; \ (head)->tqh_last = &(head)->tqh_first; \ } while (0) #define TAILQ_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ (head)->tqh_first->field.tqe_prev = \ &(elm)->field.tqe_next; \ else \ (head)->tqh_last = &(elm)->field.tqe_next; \ (head)->tqh_first = (elm); \ (elm)->field.tqe_prev = &(head)->tqh_first; \ } while (0) #define TAILQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.tqe_next = NULL; \ (elm)->field.tqe_prev = (head)->tqh_last; \ *(head)->tqh_last = (elm); \ (head)->tqh_last = &(elm)->field.tqe_next; \ } while (0) #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ (elm)->field.tqe_next->field.tqe_prev = \ &(elm)->field.tqe_next; \ else \ (head)->tqh_last = &(elm)->field.tqe_next; \ (listelm)->field.tqe_next = (elm); \ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ } while (0) #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ (elm)->field.tqe_next = (listelm); \ *(listelm)->field.tqe_prev = (elm); \ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ } while (0) #define TAILQ_REMOVE(head, elm, field) do { \ if (((elm)->field.tqe_next) != NULL) \ (elm)->field.tqe_next->field.tqe_prev = \ (elm)->field.tqe_prev; \ else \ (head)->tqh_last = (elm)->field.tqe_prev; \ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ _Q_INVALIDATE((elm)->field.tqe_prev); \ _Q_INVALIDATE((elm)->field.tqe_next); \ } while (0) #define TAILQ_REPLACE(head, elm, elm2, field) do { \ if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ (elm2)->field.tqe_next->field.tqe_prev = \ &(elm2)->field.tqe_next; \ else \ (head)->tqh_last = &(elm2)->field.tqe_next; \ (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ *(elm2)->field.tqe_prev = (elm2); \ _Q_INVALIDATE((elm)->field.tqe_prev); \ _Q_INVALIDATE((elm)->field.tqe_next); \ } while (0) /* * Circular queue definitions. */ #define CIRCLEQ_HEAD(name, type) \ struct name { \ struct type *cqh_first; /* first element */ \ struct type *cqh_last; /* last element */ \ } #define CIRCLEQ_HEAD_INITIALIZER(head) \ { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } #define CIRCLEQ_ENTRY(type) \ struct { \ struct type *cqe_next; /* next element */ \ struct type *cqe_prev; /* previous element */ \ } /* * Circular queue access methods */ #define CIRCLEQ_FIRST(head) ((head)->cqh_first) #define CIRCLEQ_LAST(head) ((head)->cqh_last) #define CIRCLEQ_END(head) ((void *)(head)) #define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) #define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) #define CIRCLEQ_EMPTY(head) \ (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head)) #define CIRCLEQ_FOREACH(var, head, field) \ for((var) = CIRCLEQ_FIRST(head); \ (var) != CIRCLEQ_END(head); \ (var) = CIRCLEQ_NEXT(var, field)) #define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ for((var) = CIRCLEQ_LAST(head); \ (var) != CIRCLEQ_END(head); \ (var) = CIRCLEQ_PREV(var, field)) /* * Circular queue functions. */ #define CIRCLEQ_INIT(head) do { \ (head)->cqh_first = CIRCLEQ_END(head); \ (head)->cqh_last = CIRCLEQ_END(head); \ } while (0) #define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ (elm)->field.cqe_next = (listelm)->field.cqe_next; \ (elm)->field.cqe_prev = (listelm); \ if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \ (head)->cqh_last = (elm); \ else \ (listelm)->field.cqe_next->field.cqe_prev = (elm); \ (listelm)->field.cqe_next = (elm); \ } while (0) #define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ (elm)->field.cqe_next = (listelm); \ (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \ (head)->cqh_first = (elm); \ else \ (listelm)->field.cqe_prev->field.cqe_next = (elm); \ (listelm)->field.cqe_prev = (elm); \ } while (0) #define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ (elm)->field.cqe_next = (head)->cqh_first; \ (elm)->field.cqe_prev = CIRCLEQ_END(head); \ if ((head)->cqh_last == CIRCLEQ_END(head)) \ (head)->cqh_last = (elm); \ else \ (head)->cqh_first->field.cqe_prev = (elm); \ (head)->cqh_first = (elm); \ } while (0) #define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.cqe_next = CIRCLEQ_END(head); \ (elm)->field.cqe_prev = (head)->cqh_last; \ if ((head)->cqh_first == CIRCLEQ_END(head)) \ (head)->cqh_first = (elm); \ else \ (head)->cqh_last->field.cqe_next = (elm); \ (head)->cqh_last = (elm); \ } while (0) #define CIRCLEQ_REMOVE(head, elm, field) do { \ if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \ (head)->cqh_last = (elm)->field.cqe_prev; \ else \ (elm)->field.cqe_next->field.cqe_prev = \ (elm)->field.cqe_prev; \ if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \ (head)->cqh_first = (elm)->field.cqe_next; \ else \ (elm)->field.cqe_prev->field.cqe_next = \ (elm)->field.cqe_next; \ _Q_INVALIDATE((elm)->field.cqe_prev); \ _Q_INVALIDATE((elm)->field.cqe_next); \ } while (0) #define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ CIRCLEQ_END(head)) \ (head).cqh_last = (elm2); \ else \ (elm2)->field.cqe_next->field.cqe_prev = (elm2); \ if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ CIRCLEQ_END(head)) \ (head).cqh_first = (elm2); \ else \ (elm2)->field.cqe_prev->field.cqe_next = (elm2); \ _Q_INVALIDATE((elm)->field.cqe_prev); \ _Q_INVALIDATE((elm)->field.cqe_next); \ } while (0) #endif /* !_JFFI_QUEUE_H_ */ jffi-1.0.2/jni/jffi/Library.c0000644000175000017500000001152211424636215015641 0ustar twernertwerner#include #include #include #include #include #if defined(_WIN32) || defined(__WIN32__) # include # include #else # include #endif #if defined (__sun) || defined(_AIX) # include #endif #include #include #include "jffi.h" #include "Exception.h" #include "com_kenai_jffi_Foreign.h" #if defined(_WIN32) || defined(__WIN32__) static void* dl_open(const char* name, int flags); static void dl_error(char* buf, int size); #define dl_sym(handle, name) GetProcAddress(handle, name) #define dl_close(handle) FreeLibrary(handle) enum { RTLD_LAZY=1, RTLD_NOW, RTLD_GLOBAL, RTLD_LOCAL }; #else # define dl_open(name, flags) dlopen(name, flags != 0 ? flags : (RTLD_LAZY | RTLD_LOCAL)) # define dl_error(buf, size) do { \ const char *e = dlerror(); snprintf(buf, size, "%s", e ? e : "unknown"); \ } while(0) # define dl_sym(handle, name) dlsym(handle, name) # define dl_close(handle) dlclose(handle) #ifndef RTLD_LOCAL # define RTLD_LOCAL 8 #endif #endif static int getMultibyteString(JNIEnv* env, char* dst, jstring jstr, int n); static int getWideString(JNIEnv* env, wchar_t* dst, jstring jstr, int n); /* * Class: com_kenai_jffi_Foreign * Method: dlopen * Signature: (Ljava/lang/String;I)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_dlopen(JNIEnv* env, jobject self, jstring jPath, jint jFlags) { #ifdef _WIN32 if (jPath == NULL) { return p2j(GetModuleHandle(NULL)); } else { wchar_t path[PATH_MAX]; getWideString(env, path, jPath, sizeof(path) / sizeof(path[0])); return p2j(LoadLibraryExW(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH)); } #else char path_[PATH_MAX]; const char* path = NULL; // Handle dlopen(NULL, flags); void* handle = NULL; int flags = 0; #define F(x) (jFlags & com_kenai_jffi_Foreign_RTLD_##x) != 0 ? RTLD_##x : 0; flags |= F(LAZY); flags |= F(GLOBAL); flags |= F(LOCAL); flags |= F(NOW); #undef F #ifdef _AIX flags |= RTLD_MEMBER; // Needed for AIX #endif if (jPath != NULL) { path = path_; getMultibyteString(env, path_, jPath, sizeof(path_)); } handle = dl_open(path, flags); if (handle == NULL) { char errbuf[1024] = { 0 }; dl_error(errbuf, sizeof(errbuf) - 1); throwException(env, UnsatisfiedLink, "%s", errbuf); } return p2j(handle); #endif } /* * Class: com_googlecode_jffi_NativeLibrary * Method: dlclose * Signature: (J)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_dlclose(JNIEnv* env, jclass cls, jlong handle) { dl_close(j2p(handle)); } JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_dlsym(JNIEnv* env, jclass cls, jlong handle, jstring jstr) { char sym[1024]; void* addr; getMultibyteString(env, sym, jstr, sizeof(sym)); #ifndef _WIN32 dlerror(); // clear any errors #endif addr = dl_sym(j2p(handle), sym); if (addr == NULL) { char errbuf[1024] = { 0 }; dl_error(errbuf, sizeof(errbuf) - 1); throwException(env, UnsatisfiedLink, "%s", errbuf); } return p2j(addr); } /* * Class: com_kenai_jffi_Foreign * Method: dlerror * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_kenai_jffi_Foreign_dlerror(JNIEnv* env, jobject self) { char errbuf[1024] = { 0 }; dl_error(errbuf, sizeof(errbuf) - 1); return (*env)->NewStringUTF(env, errbuf); } #if defined(_WIN32) || defined(__WIN32__) static void* dl_open(const char* name, int flags) { if (name == NULL) { return GetModuleHandle(NULL); } else { return LoadLibraryEx(name, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); } } static void dl_error(char* buf, int size) { FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, buf, size, NULL); } #endif static int getWideString(JNIEnv* env, wchar_t* dst, jstring src, int n) { const jchar* jstr = NULL; int len, i; if (src != NULL) { jstr = (*env)->GetStringChars(env, src, NULL); } len = (*env)->GetStringLength(env, src); if (len > (n - 1)) len = n - 1; for (i = 0; i < len; ++i) { dst[i] = (wchar_t) jstr[i]; } dst[len] = (wchar_t) 0; if (jstr != NULL) { (*env)->ReleaseStringChars(env, src, jstr); } return len; } static int getMultibyteString(JNIEnv* env, char* dst, jstring src, int n) { wchar_t* wstr = NULL; const jchar* jstr = NULL; int len, i; if (src != NULL) { jstr = (*env)->GetStringChars(env, src, NULL); } len = (*env)->GetStringLength(env, src); wstr = alloca(sizeof(wchar_t) * (len + 1)); for (i = 0; i < len; ++i) { wstr[i] = (wchar_t) jstr[i]; } wstr[len] = (wchar_t) 0; if (jstr != NULL) { (*env)->ReleaseStringChars(env, src, jstr); } return wcstombs(dst, wstr, n); } jffi-1.0.2/jni/jffi/LastError.c0000644000175000017500000000223211424636215016150 0ustar twernertwerner#include #include #ifdef _WIN32 # include #endif #include #include "LastError.h" #if defined(_WIN32) static __thread int last_error = 0; #endif /* * Class: com_kenai_jffi_Foreign * Method: getLastError * Signature: ()I */ JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_getLastError(JNIEnv* env, jobject self) { #ifdef _WIN32 // printf("Getting ERRNO: %d on thread %d\n", last_error, (int)GetCurrentThreadId()); return last_error; #else return thread_data_get()->error; #endif } /* * Class: com_kenai_jffi_Foreign * Method: setLastError * Signature: (I)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_setLastError(JNIEnv* env, jobject self, jint value) { #ifdef _WIN32 // printf("Setting ERRNO: %d on thread %d\n", value, (int)GetCurrentThreadId()); SetLastError(value); last_error = value; #else thread_data_get()->error = errno = value; #endif } void jffi_save_errno(void) { #ifdef _WIN32 last_error = GetLastError(); // printf("JFFI Saving ERRNO: %d on thread %d\n", last_error, (int)GetCurrentThreadId()); #else thread_data_get()->error = errno; #endif } jffi-1.0.2/jni/jffi/Internals.c0000644000175000017500000000056511424636215016201 0ustar twernertwerner#include #include #include "Exception.h" #include "com_kenai_jffi_Foreign.h" #include "LastError.h" #include "jffi.h" /* * Class: com_kenai_jffi_Foreign * Method: getSaveErrnoFunction * Signature: ()J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_getSaveErrnoFunction(JNIEnv *env, jobject self) { return p2j(jffi_save_errno); } jffi-1.0.2/jni/jffi/Function.c0000644000175000017500000001056511424636215016030 0ustar twernertwerner#include #include #include #include #if defined(__sun) || defined(_AIX) # include # include #endif #ifdef _WIN32 # include #endif #include #include #include "jffi.h" #include "Exception.h" #include "Function.h" #include "com_kenai_jffi_Foreign.h" #ifndef MAX # define MAX(a,b) ((a) > (b) ? (a) : (b)) #endif static inline int FFI_ALIGN(int v, int a) { return ((((size_t) v) - 1) | (a - 1)) +1; } /* * Class: com_kenai_jffi_Foreign * Method: newCallContext * Signature: (I[II)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_newFunction(JNIEnv* env, jobject self, jlong function, jlong returnType, jlongArray paramArray, jint flags) { Function* ctx = NULL; jlong* paramTypes; int paramCount, i, rawOffset = 0; ffi_type* ffiParamTypes; int ffiStatus; int abi; paramCount = (*env)->GetArrayLength(env, paramArray); ctx = calloc(1, sizeof(*ctx)); if (ctx == NULL) { throwException(env, OutOfMemory, "Failed to allocate CallContext"); goto cleanup; } ctx->ffiParamTypes = calloc(MAX(1, paramCount), sizeof(ffi_type *)); if (ctx->ffiParamTypes == NULL) { throwException(env, OutOfMemory, "Failed to allocate CallContext#ffiParamTypes"); goto cleanup; } ctx->rawParamOffsets = calloc(MAX(1, paramCount), sizeof(*ctx->rawParamOffsets)); if (ctx->rawParamOffsets == NULL) { throwException(env, OutOfMemory, "Failed to allocate CallContext#rawParamOffsets"); goto cleanup; } paramTypes = alloca(paramCount * sizeof(jlong)); (*env)->GetLongArrayRegion(env, paramArray, 0, paramCount, paramTypes); for (i = 0; i < paramCount; ++i) { ffi_type* type = (ffi_type *) j2p(paramTypes[i]); if (type == NULL) { throwException(env, IllegalArgument, "Invalid parameter type: %#x", paramTypes[i]); goto cleanup; } ctx->ffiParamTypes[i] = type; ctx->rawParamOffsets[i] = rawOffset; rawOffset += FFI_ALIGN(type->size, FFI_SIZEOF_ARG); } // On win32, we might need to set the abi to stdcall - but win64 only supports cdecl/default #if defined(_WIN32) && !defined(_WIN64) abi = (flags & com_kenai_jffi_Foreign_F_STDCALL) != 0 ? FFI_STDCALL : FFI_DEFAULT_ABI; #else abi = FFI_DEFAULT_ABI; #endif ffiStatus = ffi_prep_cif(&ctx->cif, abi, paramCount, (ffi_type *) j2p(returnType), ctx->ffiParamTypes); switch (ffiStatus) { case FFI_OK: break; case FFI_BAD_TYPEDEF: throwException(env, IllegalArgument, "Bad typedef"); goto cleanup; case FFI_BAD_ABI: throwException(env, Runtime, "Invalid ABI"); goto cleanup; default: throwException(env, Runtime, "Unknown FFI error"); } ctx->rawParameterSize = rawOffset; ctx->function = j2p(function); /* Save errno unless explicitly told not to do so */ ctx->saveErrno = (flags & com_kenai_jffi_Foreign_F_NOERRNO) == 0; return p2j(ctx); cleanup: if (ctx != NULL) { if (ctx->rawParamOffsets != NULL) { free(ctx->rawParamOffsets); } if (ctx->ffiParamTypes != NULL) { free(ctx->ffiParamTypes); } free(ctx); } return 0LL; } /* * Class: com_kenai_jffi_Foreign * Method: freeCallContext * Signature: (J)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_freeFunction(JNIEnv* env, jobject self, jlong handle) { Function* ctx = (Function *) j2p(handle); if (ctx != NULL) { if (ctx->rawParamOffsets != NULL) { free(ctx->rawParamOffsets); } if (ctx->ffiParamTypes != NULL) { free(ctx->ffiParamTypes); } free(ctx); } } /* * Class: com_kenai_jffi_Foreign * Method: getFunctionRawParameterSize * Signature: (J)I */ JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_getFunctionRawParameterSize(JNIEnv* env, jobject self, jlong handle) { Function* ctx = (Function *) j2p(handle); return ctx->rawParameterSize; } /* * Class: com_kenai_jffi_Foreign * Method: getFunctionAddress * Signature: (J)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_getFunctionAddress(JNIEnv* env, jobject self, jlong handle) { return p2j(((Function *) j2p(handle))->function); } jffi-1.0.2/jni/jffi/Exception.h0000644000175000017500000000252011424636215016176 0ustar twernertwerner/* * Copyright (C) 2008 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ #ifndef jffi_Exception_h #define jffi_Exception_h #ifdef __cplusplus extern "C" { #endif #define throwException(env, name, fmt, a...) \ jffi_throwExceptionByName((env), jffi_##name##Exception, fmt, ##a) extern const char* jffi_IllegalArgumentException; extern const char* jffi_NullPointerException; extern const char* jffi_OutOfBoundsException; extern const char* jffi_OutOfMemoryException; extern const char* jffi_RuntimeException; extern const char* jffi_UnsatisfiedLinkException; extern void jffi_throwExceptionByName(JNIEnv* env, const char* exceptionName, const char* fmt, ...); #ifdef __cplusplus } #endif #endif /* jffi_Exception_h */ jffi-1.0.2/jni/jffi/FastNumericInvoker.c0000644000175000017500000000626311424636215020021 0ustar twernertwerner#include #include #include #include #include #include "endian.h" #include "jffi.h" #include "Exception.h" #include "Function.h" #include "LastError.h" #include "com_kenai_jffi_Foreign.h" /* for return values <= sizeof(long), need to use an ffi_sarg sized return value */ #define RETVAL(retval, rtype) ((rtype)->size > sizeof(ffi_sarg) ? (retval).j : (retval).sarg) /* * Class: com_kenai_jffi_Foreign * Method: invokeVrL * Signature: (J)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeVrN(JNIEnv* env, jobject self, jlong ctxAddress) { Function* ctx = (Function *) j2p(ctxAddress); FFIValue retval; ffi_call0(ctx, ctx->function, &retval); SAVE_ERRNO(ctx); return RETVAL(retval, ctx->cif.rtype); } /* * Class: com_kenai_jffi_Foreign * Method: invokeLrL * Signature: (JJ)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeNrN(JNIEnv* env, jobject self, jlong ctxAddress, jlong arg1) { Function* ctx = (Function *) j2p(ctxAddress); FFIValue retval; ffi_call1(ctx, ctx->function, &retval, arg1); SAVE_ERRNO(ctx); return RETVAL(retval, ctx->cif.rtype); } /* * Class: com_kenai_jffi_Foreign * Method: invokeLLrL * Signature: (JJJ)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeNNrN(JNIEnv* env, jobject self, jlong ctxAddress, jlong arg1, jlong arg2) { Function* ctx = (Function *) j2p(ctxAddress); FFIValue retval; ffi_call2(ctx, ctx->function, &retval, arg1, arg2); SAVE_ERRNO(ctx); return RETVAL(retval, ctx->cif.rtype); } /* * Class: com_kenai_jffi_Foreign * Method: invokeLLLrL * Signature: (JJJJ)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeNNNrN(JNIEnv* env, jobject self, jlong ctxAddress, jlong arg1, jlong arg2, jlong arg3) { Function* ctx = (Function *) j2p(ctxAddress); FFIValue retval; ffi_call3(ctx, ctx->function, &retval, arg1, arg2, arg3); SAVE_ERRNO(ctx); return RETVAL(retval, ctx->cif.rtype); } JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeNNNNrN(JNIEnv* env, jobject self, jlong ctxAddress, jlong arg1, jlong arg2, jlong arg3, jlong arg4) { Function* ctx = (Function *) j2p(ctxAddress); FFIValue retval; ffi_call4(ctx, ctx->function, &retval, arg1, arg2, arg3, arg4); SAVE_ERRNO(ctx); return RETVAL(retval, ctx->cif.rtype); } JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeNNNNNrN(JNIEnv* env, jobject self, jlong ctxAddress, jlong arg1, jlong arg2, jlong arg3, jlong arg4, jlong arg5) { Function* ctx = (Function *) j2p(ctxAddress); FFIValue retval; ffi_call5(ctx, ctx->function, &retval, arg1, arg2, arg3, arg4, arg5); SAVE_ERRNO(ctx); return RETVAL(retval, ctx->cif.rtype); } JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeNNNNNNrN(JNIEnv* env, jobject self, jlong ctxAddress, jlong arg1, jlong arg2, jlong arg3, jlong arg4, jlong arg5, jlong arg6) { Function* ctx = (Function *) j2p(ctxAddress); FFIValue retval; ffi_call6(ctx, ctx->function, &retval, arg1, arg2, arg3, arg4, arg5, arg6); SAVE_ERRNO(ctx); return RETVAL(retval, ctx->cif.rtype); } jffi-1.0.2/jni/jffi/Foreign.c0000644000175000017500000000772211424636215015635 0ustar twernertwerner#include #ifndef _WIN32 # include #endif #include #include "Exception.h" #include "com_kenai_jffi_Foreign.h" #include "com_kenai_jffi_Version.h" #include "jffi.h" #ifndef _WIN32 pthread_key_t jffi_threadDataKey; static void thread_data_free(void *ptr); #endif JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { #ifndef _WIN32 pthread_key_create(&jffi_threadDataKey, thread_data_free); #endif return JNI_VERSION_1_4; } #ifndef _WIN32 ThreadData* jffi_thread_data_init() { ThreadData* td = calloc(1, sizeof(*td)); pthread_setspecific(jffi_threadDataKey, td); return td; } static void thread_data_free(void *ptr) { free(ptr); } #endif /* !_WIN32 */ JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_getVersion(JNIEnv* env, jobject self) { return (com_kenai_jffi_Version_MAJOR << 16) | (com_kenai_jffi_Version_MINOR << 8) | (com_kenai_jffi_Version_MICRO); } /* * Class: com_kenai_jffi_Foreign * Method: init * Signature: ()V * * Initialize any class/method/field ids */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_init(JNIEnv* env, jobject self) { } JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_getJNIVersion(JNIEnv* env, jobject self) { return (*env)->GetVersion(env); } JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_getJavaVM(JNIEnv *env, jobject self) { JavaVM* vm; (*env)->GetJavaVM(env, &vm); return p2j(vm); } JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_fatalError(JNIEnv * env, jobject self, jstring msg) { const char* str = (*env)->GetStringUTFChars(env, msg, NULL); (*env)->FatalError(env, str); (*env)->ReleaseStringUTFChars(env, msg, str); } JNIEXPORT jclass JNICALL Java_com_kenai_jffi_Foreign_defineClass__Ljava_lang_String_2Ljava_lang_Object_2_3BII(JNIEnv *env, jobject self, jstring jname, jobject loader, jbyteArray jbuf, jint off, jint len) { const char* name = NULL; jbyte* buf = NULL; jclass retval = NULL; name = (*env)->GetStringUTFChars(env, jname, NULL); if (name == NULL) { throwException(env, NullPointer, "Invalid name parameter"); goto cleanup; } buf = (*env)->GetByteArrayElements(env, jbuf, NULL); if (buf == NULL) { throwException(env, NullPointer, "Invalid buffer parameter"); goto cleanup; } retval = (*env)->DefineClass(env, name, loader, buf + off, len); cleanup: if (buf != NULL) { (*env)->ReleaseByteArrayElements(env, jbuf, buf, JNI_ABORT); } if (name != NULL) { (*env)->ReleaseStringUTFChars(env, jname, name); } return retval; } JNIEXPORT jclass JNICALL Java_com_kenai_jffi_Foreign_defineClass__Ljava_lang_String_2Ljava_lang_Object_2Ljava_nio_ByteBuffer_2(JNIEnv *env, jobject self, jstring jname, jobject loader, jobject jbuf) { const char* name = NULL; jclass retval = NULL; name = (*env)->GetStringUTFChars(env, jname, NULL); if (name == NULL) { throwException(env, NullPointer, "Invalid name parameter"); goto cleanup; } if (jbuf == NULL) { throwException(env, NullPointer, "Invalid buffer parameter"); goto cleanup; } retval = (*env)->DefineClass(env, name, loader, (*env)->GetDirectBufferAddress(env, jbuf), (*env)->GetDirectBufferCapacity(env, jbuf)); cleanup: if (name != NULL) { (*env)->ReleaseStringUTFChars(env, jname, name); } return retval; } JNIEXPORT jobject JNICALL Java_com_kenai_jffi_Foreign_allocObject(JNIEnv *env, jobject self, jclass klass) { return (*env)->AllocObject(env, klass); } JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_registerNatives(JNIEnv *env, jobject self, jclass clazz, jlong methods, jint nmethods) { return (*env)->RegisterNatives(env, clazz, j2p(methods), nmethods); } JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_unregisterNatives(JNIEnv *env, jobject self, jclass clazz) { return (*env)->UnregisterNatives(env, clazz); } jffi-1.0.2/jni/jffi/Type.c0000644000175000017500000000521411424636215015157 0ustar twernertwerner#include #include #include #include "com_kenai_jffi_Foreign.h" #include "jffi.h" static ffi_type* typeToFFI(int type) { switch (type) { case com_kenai_jffi_Foreign_TYPE_VOID: return &ffi_type_void; case com_kenai_jffi_Foreign_TYPE_FLOAT:return &ffi_type_float; case com_kenai_jffi_Foreign_TYPE_DOUBLE: return &ffi_type_double; case com_kenai_jffi_Foreign_TYPE_LONGDOUBLE: return &ffi_type_longdouble; case com_kenai_jffi_Foreign_TYPE_UINT8: return &ffi_type_uint8; case com_kenai_jffi_Foreign_TYPE_SINT8: return &ffi_type_sint8; case com_kenai_jffi_Foreign_TYPE_UINT16: return &ffi_type_uint16; case com_kenai_jffi_Foreign_TYPE_SINT16: return &ffi_type_sint16; case com_kenai_jffi_Foreign_TYPE_UINT32: return &ffi_type_uint32; case com_kenai_jffi_Foreign_TYPE_SINT32: return &ffi_type_sint32; case com_kenai_jffi_Foreign_TYPE_UINT64: return &ffi_type_uint64; case com_kenai_jffi_Foreign_TYPE_SINT64: return &ffi_type_sint64; case com_kenai_jffi_Foreign_TYPE_POINTER: return &ffi_type_pointer; case com_kenai_jffi_Foreign_TYPE_UCHAR: return &ffi_type_uchar; case com_kenai_jffi_Foreign_TYPE_SCHAR: return &ffi_type_schar; case com_kenai_jffi_Foreign_TYPE_USHORT: return &ffi_type_ushort; case com_kenai_jffi_Foreign_TYPE_SSHORT: return &ffi_type_sshort; case com_kenai_jffi_Foreign_TYPE_UINT: return &ffi_type_uint; case com_kenai_jffi_Foreign_TYPE_SINT: return &ffi_type_sint; case com_kenai_jffi_Foreign_TYPE_ULONG: return &ffi_type_ulong; case com_kenai_jffi_Foreign_TYPE_SLONG: return &ffi_type_slong; } return NULL; } /* * Class: com_kenai_jffi_Foreign * Method: lookupType * Signature: (I)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_lookupBuiltinType(JNIEnv* env, jobject self, jint type) { return p2j(typeToFFI(type)); } /* * Class: com_kenai_jffi_Foreign * Method: getTypeSize * Signature: (J)I */ JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_getTypeSize(JNIEnv* env, jobject self, jlong handle) { return ((ffi_type *) j2p(handle))->size; } /* * Class: com_kenai_jffi_Foreign * Method: getTypeAlign * Signature: (J)I */ JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_getTypeAlign(JNIEnv* env, jobject self, jlong handle) { return ((ffi_type *) j2p(handle))->alignment; } /* * Class: com_kenai_jffi_Foreign * Method: getTypeType * Signature: (J)I */ JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_getTypeType(JNIEnv* env, jobject self, jlong handle) { return ((ffi_type *) j2p(handle))->type; } jffi-1.0.2/jni/jffi/CallContext.c0000644000175000017500000001012611424636215016454 0ustar twernertwerner#include #include #include #include #if defined(__sun) || defined(_AIX) # include # include #endif #ifdef _WIN32 # include #endif #include #include #include "jffi.h" #include "Exception.h" #include "CallContext.h" #include "com_kenai_jffi_Foreign.h" #ifndef MAX # define MAX(a,b) ((a) > (b) ? (a) : (b)) #endif static inline int FFI_ALIGN(int v, int a) { return ((((size_t) v) - 1) | (a - 1)) +1; } /* * Class: com_kenai_jffi_Foreign * Method: newCallContext * Signature: (I[II)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_newCallContext(JNIEnv* env, jobject self, jlong returnType, jlongArray paramArray, jint flags) { CallContext* ctx = NULL; jlong* paramTypes; int paramCount, i, rawOffset = 0; ffi_type* ffiParamTypes; int ffiStatus; int abi; paramCount = (*env)->GetArrayLength(env, paramArray); ctx = calloc(1, sizeof(*ctx)); if (ctx == NULL) { throwException(env, OutOfMemory, "Failed to allocate CallContext"); goto cleanup; } ctx->ffiParamTypes = calloc(MAX(1, paramCount), sizeof(ffi_type *)); if (ctx->ffiParamTypes == NULL) { throwException(env, OutOfMemory, "Failed to allocate CallContext#ffiParamTypes"); goto cleanup; } ctx->rawParamOffsets = calloc(MAX(1, paramCount), sizeof(*ctx->rawParamOffsets)); if (ctx->rawParamOffsets == NULL) { throwException(env, OutOfMemory, "Failed to allocate CallContext#rawParamOffsets"); goto cleanup; } paramTypes = alloca(paramCount * sizeof(jlong)); (*env)->GetLongArrayRegion(env, paramArray, 0, paramCount, paramTypes); for (i = 0; i < paramCount; ++i) { ffi_type* type = (ffi_type *) j2p(paramTypes[i]); if (type == NULL) { throwException(env, IllegalArgument, "Invalid parameter type: %#x", paramTypes[i]); goto cleanup; } ctx->ffiParamTypes[i] = type; ctx->rawParamOffsets[i] = rawOffset; rawOffset += FFI_ALIGN(type->size, FFI_SIZEOF_ARG); } // On win32, we might need to set the abi to stdcall - but win64 only supports cdecl/default #if defined(_WIN32) && !defined(_WIN64) abi = (flags & com_kenai_jffi_Foreign_F_STDCALL) != 0 ? FFI_STDCALL : FFI_DEFAULT_ABI; #else abi = FFI_DEFAULT_ABI; #endif ffiStatus = ffi_prep_cif(&ctx->cif, abi, paramCount, (ffi_type *) j2p(returnType), ctx->ffiParamTypes); switch (ffiStatus) { case FFI_OK: break; case FFI_BAD_TYPEDEF: throwException(env, IllegalArgument, "Bad typedef"); goto cleanup; case FFI_BAD_ABI: throwException(env, Runtime, "Invalid ABI"); goto cleanup; default: throwException(env, Runtime, "Unknown FFI error"); } ctx->rawParameterSize = rawOffset; /* Save errno unless explicitly told not to do so */ ctx->saveErrno = (flags & com_kenai_jffi_Foreign_F_NOERRNO) == 0; return p2j(ctx); cleanup: if (ctx != NULL) { if (ctx->rawParamOffsets != NULL) { free(ctx->rawParamOffsets); } if (ctx->ffiParamTypes != NULL) { free(ctx->ffiParamTypes); } free(ctx); } return 0LL; } /* * Class: com_kenai_jffi_Foreign * Method: freeCallContext * Signature: (J)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_freeCallContext(JNIEnv* env, jobject self, jlong handle) { CallContext* ctx = (CallContext *) j2p(handle); if (ctx != NULL) { if (ctx->rawParamOffsets != NULL) { free(ctx->rawParamOffsets); } if (ctx->ffiParamTypes != NULL) { free(ctx->ffiParamTypes); } free(ctx); } } /* * Class: com_kenai_jffi_Foreign * Method: getCallContextRawParameterSize * Signature: (J)I */ JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_getCallContextRawParameterSize(JNIEnv* env, jobject self, jlong handle) { CallContext* ctx = (CallContext *) j2p(handle); return ctx->rawParameterSize; } jffi-1.0.2/jni/jffi/ClosureMagazine.c0000644000175000017500000001560511424636215017333 0ustar twernertwerner/* * Copyright (C) 2007-2009 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ #include #include #include #include #include #include #if defined(__sun) || defined(_AIX) # include # include #endif #ifdef _WIN32 # include #endif #include #include "jffi.h" #include "Exception.h" #include "Type.h" #include "CallContext.h" #include "MemoryUtil.h" #include "com_kenai_jffi_Foreign.h" struct Closure; typedef struct ClosureMagazine { CallContext* callContext; jmethodID methodID; JavaVM* jvm; void* code; struct Closure* closures; int nclosures; int nextclosure; } Magazine; typedef struct Closure { void* code; /* the code address must be the first member of this struct; used by java */ jobject javaObject; Magazine* magazine; } Closure; static bool closure_prep(ffi_cif* cif, void* code, Closure* closure, char* errbuf, size_t errbufsize); JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_newClosureMagazine(JNIEnv *env, jobject self, jlong ctxAddress, jobject closureMethod) { CallContext* ctx = (CallContext *) j2p(ctxAddress); Closure* list = NULL; Magazine* magazine = NULL; caddr_t code = NULL; char errmsg[256]; int i; int trampolineSize, pageSize, nclosures; trampolineSize = roundup(sizeof(ffi_closure), 8); pageSize = jffi_getPageSize(); nclosures = pageSize / trampolineSize; magazine = calloc(1, sizeof(*magazine)); list = calloc(nclosures, sizeof(*list)); code = jffi_allocatePages(1); if (magazine == NULL || list == NULL || code == NULL) { snprintf(errmsg, sizeof(errmsg), "failed to allocate a page. errno=%d (%s)", errno, strerror(errno)); goto error; } // Thread all the closure handles onto a list, and init each one for (i = 0; i < nclosures; ++i) { Closure* closure = &list[i]; closure->magazine = magazine; closure->code = (code + (i * trampolineSize)); if (!closure_prep(&ctx->cif, closure->code, closure, errmsg, sizeof(errmsg))) { goto error; } } if (!jffi_makePagesExecutable(code, 1)) { snprintf(errmsg, sizeof(errmsg), "failed to make page executable. errno=%d (%s)", errno, strerror(errno)); goto error; } magazine->methodID = (*env)->FromReflectedMethod(env, closureMethod); if (magazine->methodID == NULL) { throwException(env, IllegalArgument, "could not obtain reference to closure method"); goto error; } /* Track the allocated page + Closure memory area */ magazine->closures = list; magazine->nextclosure = 0; magazine->nclosures = nclosures; magazine->code = code; (*env)->GetJavaVM(env, &magazine->jvm); return p2j(magazine); error: free(list); free(magazine); if (code != NULL) { jffi_freePages(code, 1); } throwException(env, Runtime, errmsg); return 0L; } /* * Class: com_kenai_jffi_Foreign * Method: freeClosureMagazine * Signature: (J)V */ JNIEXPORT void JNICALL Java_com_kenai_jffi_Foreign_freeClosureMagazine(JNIEnv *env, jobject self, jlong magAddress) { Magazine* magazine = (Magazine *) j2p(magAddress); Closure* closure; int i; for (i = 0; i < magazine->nextclosure; ++i) { (*env)->DeleteGlobalRef(env, magazine->closures[i].javaObject); } free(magazine->closures); jffi_freePages(magazine->code, 1); free(magazine); } /* * Class: com_kenai_jffi_Foreign * Method: closureMagazineGet * Signature: (JLjava/lang/Object;)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_closureMagazineGet(JNIEnv *env, jobject self, jlong magAddress, jobject closureProxy) { Magazine* magazine = (Magazine *) j2p(magAddress); if (magazine->nextclosure < magazine->nclosures) { Closure* closure = &magazine->closures[magazine->nextclosure]; closure->javaObject = (*env)->NewGlobalRef(env, closureProxy); if (closure->javaObject == NULL) { throwException(env, IllegalArgument, "could not obtain reference to java object"); return 0L; } magazine->nextclosure++; return p2j(closure); } return 0L; } static void closure_begin(Closure* closure, JNIEnv** penv, bool* detach) { JavaVM* jvm = closure->magazine->jvm; *detach = (*jvm)->GetEnv(jvm, (void **)penv, JNI_VERSION_1_4) != JNI_OK && (*jvm)->AttachCurrentThreadAsDaemon(jvm, (void **)penv, NULL) == JNI_OK; if ((**penv)->ExceptionCheck(*penv)) { (**penv)->ExceptionClear(*penv); } } static void closure_end(Closure* closure, JNIEnv* env, bool detach) { JavaVM* jvm = closure->magazine->jvm; if (detach && env != NULL) { if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionClear(env); } (*jvm)->DetachCurrentThread(jvm); } } static void closure_invoke(ffi_cif* cif, void* retval, void** parameters, void* user_data) { Closure* closure = (Closure *) user_data; JNIEnv* env; jvalue javaParams[3]; bool detach; closure_begin(closure, &env, &detach); javaParams[0].j = p2j(retval); javaParams[1].j = p2j(parameters); // // Do the actual invoke - the java code will unmarshal the arguments // (*env)->CallVoidMethodA(env, closure->javaObject, closure->magazine->methodID, &javaParams[0]); closure_end(closure, env, detach); } static bool closure_prep(ffi_cif* cif, void* code, Closure* closure, char* errbuf, size_t errbufsize) { ffi_status status; status = ffi_prep_closure(code, cif, closure_invoke, closure); switch (status) { case FFI_OK: return true; case FFI_BAD_ABI: snprintf(errbuf, errbufsize, "Invalid ABI specified"); //throwException(env, IllegalArgument, "Invalid ABI specified"); return false; case FFI_BAD_TYPEDEF: snprintf(errbuf, errbufsize, "Invalid argument type specified"); //throwException(env, IllegalArgument, "Invalid argument type specified"); return false; default: snprintf(errbuf, errbufsize, "Unknown FFI error"); //throwException(env, IllegalArgument, "Unknown FFI error"); return false; } } jffi-1.0.2/jni/jffi/FastLongInvoke.c0000644000175000017500000001060711424636215017131 0ustar twernertwerner#include #include #include #include #include #include "endian.h" #include "jffi.h" #include "Exception.h" #include "Function.h" #include "LastError.h" #include "com_kenai_jffi_Foreign.h" /* for return values <= sizeof(long), need to use an ffi_sarg sized return value */ #define RETVAL(retval, rtype) ((rtype)->size > sizeof(ffi_sarg) ? (retval).j : (retval).sarg) #if defined(__x86_64__) # define LONG_BYPASS_FFI #endif /* * Class: com_kenai_jffi_Foreign * Method: invokeVrL * Signature: (J)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeVrL(JNIEnv* env, jobject self, jlong ctxAddress) { Function* ctx = (Function *) j2p(ctxAddress); #ifdef LONG_BYPASS_FFI jlong retval = ((jlong (*)(void)) (ctx->function))(); \ SAVE_ERRNO(ctx); return retval; #else FFIValue retval; ffi_call0(ctx, ctx->function, &retval); SAVE_ERRNO(ctx); return RETVAL(retval, ctx->cif.rtype); #endif } /* * Class: com_kenai_jffi_Foreign * Method: invokeLrL * Signature: (JJ)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeLrL(JNIEnv* env, jobject self, jlong ctxAddress, jlong arg1) { Function* ctx = (Function *) j2p(ctxAddress); #ifdef LONG_BYPASS_FFI jlong retval = ((jlong (*)(jlong)) (ctx->function))(arg1); \ SAVE_ERRNO(ctx); return retval; #else FFIValue retval; ffi_call1(ctx, ctx->function, &retval, arg1); SAVE_ERRNO(ctx); return RETVAL(retval, ctx->cif.rtype); #endif } /* * Class: com_kenai_jffi_Foreign * Method: invokeLLrL * Signature: (JJJ)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeLLrL(JNIEnv* env, jobject self, jlong ctxAddress, jlong arg1, jlong arg2) { Function* ctx = (Function *) j2p(ctxAddress); #ifdef LONG_BYPASS_FFI jlong retval = ((jlong (*)(jlong, jlong)) (ctx->function))(arg1, arg2); \ SAVE_ERRNO(ctx); return retval; #else FFIValue retval; ffi_call2(ctx, ctx->function, &retval, arg1, arg2); SAVE_ERRNO(ctx); return RETVAL(retval, ctx->cif.rtype); #endif } /* * Class: com_kenai_jffi_Foreign * Method: invokeLLLrL * Signature: (JJJJ)J */ JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeLLLrL(JNIEnv* env, jobject self, jlong ctxAddress, jlong arg1, jlong arg2, jlong arg3) { Function* ctx = (Function *) j2p(ctxAddress); #ifdef LONG_BYPASS_FFI jlong retval = ((jlong (*)(jlong, jlong, jlong)) (ctx->function))(arg1, arg2, arg3); SAVE_ERRNO(ctx); return retval; #else FFIValue retval; ffi_call3(ctx, ctx->function, &retval, arg1, arg2, arg3); SAVE_ERRNO(ctx); return RETVAL(retval, ctx->cif.rtype); #endif } JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeLLLLrL(JNIEnv* env, jobject self, jlong ctxAddress, jlong arg1, jlong arg2, jlong arg3, jlong arg4) { Function* ctx = (Function *) j2p(ctxAddress); #ifdef LONG_BYPASS_FFI jlong retval = ((jlong (*)(jlong, jlong, jlong, jlong)) (ctx->function))(arg1, arg2, arg3, arg4); SAVE_ERRNO(ctx); return retval; #else FFIValue retval; ffi_call4(ctx, ctx->function, &retval, arg1, arg2, arg3, arg4); SAVE_ERRNO(ctx); return RETVAL(retval, ctx->cif.rtype); #endif } JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeLLLLLrL(JNIEnv* env, jobject self, jlong ctxAddress, jlong arg1, jlong arg2, jlong arg3, jlong arg4, jlong arg5) { Function* ctx = (Function *) j2p(ctxAddress); #ifdef LONG_BYPASS_FFI jlong retval = ((jlong (*)(jlong, jlong, jlong, jlong, jlong)) (ctx->function))(arg1, arg2, arg3, arg4, arg5); SAVE_ERRNO(ctx); return retval; #else FFIValue retval; ffi_call5(ctx, ctx->function, &retval, arg1, arg2, arg3, arg4, arg5); SAVE_ERRNO(ctx); return RETVAL(retval, ctx->cif.rtype); #endif } JNIEXPORT jlong JNICALL Java_com_kenai_jffi_Foreign_invokeLLLLLLrL(JNIEnv* env, jobject self, jlong ctxAddress, jlong arg1, jlong arg2, jlong arg3, jlong arg4, jlong arg5, jlong arg6) { Function* ctx = (Function *) j2p(ctxAddress); #ifdef LONG_BYPASS_FFI jlong retval = ((jlong (*)(jlong, jlong, jlong, jlong, jlong, jlong)) (ctx->function))(arg1, arg2, arg3, arg4, arg5, arg6); SAVE_ERRNO(ctx); return retval; #else FFIValue retval; ffi_call6(ctx, ctx->function, &retval, arg1, arg2, arg3, arg4, arg5, arg6); SAVE_ERRNO(ctx); return RETVAL(retval, ctx->cif.rtype); #endif } jffi-1.0.2/jni/jffi/FastIntInvoke.c0000644000175000017500000001671711424636215016774 0ustar twernertwerner#include #include #include #include #include #include "endian.h" #include "jffi.h" #include "Exception.h" #include "Function.h" #include "LastError.h" #include "com_kenai_jffi_Foreign.h" typedef unsigned int u32; #if defined(__i386__) # define INT_BYPASS_FFI # define FLOAT_BYPASS_FFI #elif defined(__x86_64__) # define INT_BYPASS_FFI #endif #if defined(INT_BYPASS_FFI) # define invokeVrI(ctx, fn, retval) do { \ *(retval) = ((jint (*)()) (fn))(); \ } while (0) # define invokeIrI(ctx, fn, retval, arg1) do { \ *(retval) = ((jint (*)(jint)) (fn))(arg1); \ } while (0) # define invokeIIrI(ctx, fn, retval, arg1, arg2) do { \ *(retval) = ((jint (*)(jint, jint)) (fn))((arg1), (arg2)); \ } while (0) # define invokeIIIrI(ctx, fn, retval, arg1, arg2, arg3) do { \ *(retval) = ((jint (*)(jint, jint, jint)) (fn))(arg1, arg2, arg3); \ } while (0) # define invokeIIIIrI(ctx, fn, retval, arg1, arg2, arg3, arg4) do { \ *(retval) = ((jint (*)(jint, jint, jint, jint)) (fn))(arg1, arg2, arg3, arg4); \ } while (0) # define invokeIIIIIrI(ctx, fn, retval, arg1, arg2, arg3, arg4, arg5) do { \ *(retval) = ((jint (*)(jint, jint, jint, jint, jint)) (fn))(arg1, arg2, arg3, arg4, arg5); \ } while (0) # define invokeIIIIIIrI(ctx, fn, retval, arg1, arg2, arg3, arg4, arg5, arg6) do { \ *(retval) = ((jint (*)(jint, jint, jint, jint, jint, jint)) (fn))(arg1, arg2, arg3, arg4, arg5, arg6); \ } while (0) #else /* non-i386, non-x86_64 */ # define invokeVrI ffi_call0 # define invokeIrI ffi_call1 # define invokeIIrI ffi_call2 # define invokeIIIrI ffi_call3 # define invokeIIIIrI ffi_call4 # define invokeIIIIIrI ffi_call5 # define invokeIIIIIIrI ffi_call6 #endif #if defined(FLOAT_BYPASS_FFI) # define invokeVrF(ctx, fn, rvp) \ *(float *) (rvp) = ((float (*)(void)) (fn))() # define invokeIrF(ctx, fn, rvp, arg1) \ *(float *) (rvp) = ((float (*)(int)) (fn))(arg1) # define invokeIIrF(ctx, fn, rvp, arg1, arg2) \ *(float *) (rvp) = ((float (*)(int, int)) (fn))(arg1, arg2) # define invokeIIIrF(ctx, fn, rvp, arg1, arg2, arg3) \ *(float *) (rvp) = ((float (*)(int, int, int)) (fn))(arg1, arg2, arg3) #else # define invokeVrF ffi_call0 # define invokeIrF ffi_call1 # define invokeIIrF ffi_call2 # define invokeIIIrF ffi_call3 #endif #if defined(FLOAT_BYPASS_FFI) && defined(__i386__) // Doing the test before the call produces slightly better i386 asm for float calls # define CALL(ctx, stmt) do { \ if (likely(!ctx->saveErrno)) { \ stmt; \ } else { \ stmt; \ jffi_save_errno(); \ } \ } while (0) #else // This version produces smaller code for ffi_call paths # define CALL(ctx, stmt) do { stmt; SAVE_ERRNO(ctx); } while(0) #endif /* * Class: com_kenai_jffi_Foreign * Method: invokeVrI * Signature: (J)I */ JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_invokeVrI(JNIEnv* env, jclass self, jlong ctxAddress) { Function* ctx = (Function *) j2p(ctxAddress); ffi_sarg retval; CALL(ctx, invokeVrI(ctx, ctx->function, &retval)); return (jint) retval; } /* * Class: com_kenai_jffi_Foreign * Method: invokeVrI * Signature: (J)I */ JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_invokeNoErrnoVrI(JNIEnv* env, jclass self, jlong ctxAddress) { Function* ctx = (Function *) j2p(ctxAddress); ffi_sarg retval; invokeVrI(ctx, ctx->function, &retval); return (jint) retval; } JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_invokeIrI(JNIEnv* env, jclass self, jlong ctxAddress, jint arg1) { Function* ctx = (Function *) j2p(ctxAddress); ffi_sarg retval; CALL(ctx, invokeIrI(ctx, ctx->function, &retval, arg1)); return (jint) retval; } JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_invokeNoErrnoIrI(JNIEnv* env, jclass self, jlong ctxAddress, jint arg1) { Function* ctx = (Function *) j2p(ctxAddress); ffi_sarg retval; invokeIrI(ctx, ctx->function, &retval, arg1); return (int) retval; } JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_invokeIIrI(JNIEnv*env, jobject self, jlong ctxAddress, jint arg1, jint arg2) { Function* ctx = (Function *) j2p(ctxAddress); ffi_sarg retval; CALL(ctx, invokeIIrI(ctx, ctx->function, &retval, arg1, arg2)); return (jint) retval; } JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_invokeNoErrnoIIrI(JNIEnv*env, jobject self, jlong ctxAddress, jint arg1, jint arg2) { Function* ctx = (Function *) j2p(ctxAddress); ffi_sarg retval; invokeIIrI(ctx, ctx->function, &retval, arg1, arg2); return (int) retval; } JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_invokeIIIrI(JNIEnv*env, jobject self, jlong ctxAddress, jint arg1, jint arg2, jint arg3) { Function* ctx = (Function *) j2p(ctxAddress); ffi_sarg retval; CALL(ctx, invokeIIIrI(ctx, ctx->function, &retval, arg1, arg2, arg3)); return (jint) retval; } JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_invokeIIIIrI(JNIEnv*env, jobject self, jlong ctxAddress, jint arg1, jint arg2, jint arg3, jint arg4) { Function* ctx = (Function *) j2p(ctxAddress); ffi_sarg retval; CALL(ctx, invokeIIIIrI(ctx, ctx->function, &retval, arg1, arg2, arg3, arg4)); return (jint) retval; } JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_invokeIIIIIrI(JNIEnv*env, jobject self, jlong ctxAddress, jint arg1, jint arg2, jint arg3, jint arg4, jint arg5) { Function* ctx = (Function *) j2p(ctxAddress); ffi_sarg retval; CALL(ctx, invokeIIIIIrI(ctx, ctx->function, &retval, arg1, arg2, arg3, arg4, arg5)); return (jint) retval; } JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_invokeIIIIIIrI(JNIEnv*env, jobject self, jlong ctxAddress, jint arg1, jint arg2, jint arg3, jint arg4, jint arg5, jint arg6) { Function* ctx = (Function *) j2p(ctxAddress); ffi_sarg retval; CALL(ctx, invokeIIIIIIrI(ctx, ctx->function, &retval, arg1, arg2, arg3, arg4, arg5, arg6)); return (jint) retval; } JNIEXPORT jint JNICALL Java_com_kenai_jffi_Foreign_invokeNoErrnoIIIrI(JNIEnv*env, jobject self, jlong ctxAddress, jint arg1, jint arg2, jint arg3) { Function* ctx = (Function *) j2p(ctxAddress); ffi_sarg retval; invokeIIIrI(ctx, ctx->function, &retval, arg1, arg2, arg3); return (int) retval; } JNIEXPORT jfloat JNICALL Java_com_kenai_jffi_Foreign_invokeVrF(JNIEnv* env, jclass self, jlong ctxAddress) { Function* ctx = (Function *) j2p(ctxAddress); float retval; CALL(ctx, invokeVrF(ctx, ctx->function, &retval)); return retval; } JNIEXPORT jfloat JNICALL Java_com_kenai_jffi_Foreign_invokeIrF(JNIEnv* env, jclass self, jlong ctxAddress, jint arg1) { Function* ctx = (Function *) j2p(ctxAddress); float retval; CALL(ctx, invokeIrF(ctx, ctx->function, &retval, arg1)); return retval; } JNIEXPORT jfloat JNICALL Java_com_kenai_jffi_Foreign_invokeIIrF(JNIEnv*env, jobject self, jlong ctxAddress, jint arg1, jint arg2) { Function* ctx = (Function *) j2p(ctxAddress); float retval; CALL(ctx, invokeIIrF(ctx, ctx->function, &retval, arg1, arg2)); return retval; } JNIEXPORT jfloat JNICALL Java_com_kenai_jffi_Foreign_invokeIIIrF(JNIEnv*env, jobject self, jlong ctxAddress, jint arg1, jint arg2, jint arg3) { Function* ctx = (Function *) j2p(ctxAddress); float retval; CALL(ctx, invokeIIIrF(ctx, ctx->function, &retval, arg1, arg2, arg3)); return retval; } jffi-1.0.2/jni/jffi/Type.h0000644000175000017500000000012511424636215015160 0ustar twernertwerner#ifndef JFFI_TYPE_H #define JFFI_TYPE_H #include #endif /* JFFI_TYPE_H */ jffi-1.0.2/jni/jffi/jffi.h0000755000175000017500000001237711424636215015174 0ustar twernertwerner/* * Copyright (C) 2007, 2008 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ #ifndef jffi_jffi_h #define jffi_jffi_h #include #include #include #include #ifndef _WIN32 # include #endif #include "endian.h" #include #include #ifdef __cplusplus extern "C" { #endif #ifndef roundup # define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) #endif #ifdef _WIN32 typedef char* caddr_t; #endif #ifdef __GNUC__ # define likely(x) __builtin_expect((x), 1) # define unlikely(x) __builtin_expect((x), 0) #else # define likely(x) (x) # define unlikely(x) (x) #endif /** * Convert a C pointer into a java long */ static inline jlong p2j(void *p) { return (jlong)(uintptr_t) p; } /** * Convert a java long into a C pointer */ static inline void* j2p(jlong j) { return (void *)(uintptr_t) j; } #ifndef __cplusplus static inline jboolean loadClass(JNIEnv* env, const char *name, jclass *classp) { jclass tmp = (*env)->FindClass(env, name); if (tmp == NULL) { return JNI_FALSE; } *classp = (jclass)(*env)->NewGlobalRef(env, tmp); return JNI_TRUE; } #endif typedef union FFIValue { int8_t s8; uint8_t u8; int16_t s16; uint16_t u16; int32_t s32; uint32_t u32; int64_t s64; uint64_t u64; jint i; jlong j; long l; float f; double d; void* p; ffi_sarg sarg; ffi_arg arg; } FFIValue; #ifndef _WIN32 typedef struct ThreadData { int error; } ThreadData; extern pthread_key_t jffi_threadDataKey; extern ThreadData* jffi_thread_data_init(); static inline ThreadData* thread_data_get() { ThreadData* td = (ThreadData *) pthread_getspecific(jffi_threadDataKey); return likely(td != NULL) ? td : jffi_thread_data_init(); } #endif /* !_WIN32 */ #if defined(__i386__) # define USE_RAW 1 #endif #if BYTE_ORDER == LITTLE_ENDIAN # define return_int(retval) return ((retval).i) # define ARGPTR(argp, type) (argp) #elif BYTE_ORDER == BIG_ENDIAN # define return_int(retval) return ((retval).l & 0xFFFFFFFFL) # define ARGPTR(argp, type) (((caddr_t) (argp)) + sizeof(*argp) - (type)->size) #else # error "Unsupported BYTE_ORDER" #endif # define ffi_call0(ctx, fn, retval) do { \ FFIValue arg0; \ void* ffiValues[] = { &arg0 }; \ ffi_call(&(ctx)->cif, FFI_FN((fn)), (retval), ffiValues); \ } while (0) # define ffi_call1(ctx, fn, retval, arg1) do { \ void* ffiValues[] = { ARGPTR(&(arg1), (ctx)->cif.arg_types[0]) }; \ ffi_call(&(ctx)->cif, FFI_FN((fn)), (retval), ffiValues); \ } while (0) # define ffi_call2(ctx, fn, retval, arg1, arg2) do {\ void* ffiValues[] = { \ ARGPTR(&arg1, (ctx)->cif.arg_types[0]), \ ARGPTR(&arg2, (ctx)->cif.arg_types[1]) \ }; \ ffi_call(&(ctx)->cif, FFI_FN((fn)), (retval), ffiValues); \ } while (0) # define ffi_call3(ctx, fn, retval, arg1, arg2, arg3) do { \ void* ffiValues[] = { \ ARGPTR(&arg1, (ctx)->cif.arg_types[0]), \ ARGPTR(&arg2, (ctx)->cif.arg_types[1]), \ ARGPTR(&arg3, (ctx)->cif.arg_types[2]) \ }; \ ffi_call(&(ctx)->cif, FFI_FN((fn)), (retval), ffiValues); \ } while (0) # define ffi_call4(ctx, fn, retval, arg1, arg2, arg3, arg4) do { \ void* ffiValues[] = { \ ARGPTR(&arg1, (ctx)->cif.arg_types[0]), \ ARGPTR(&arg2, (ctx)->cif.arg_types[1]), \ ARGPTR(&arg3, (ctx)->cif.arg_types[2]), \ ARGPTR(&arg4, (ctx)->cif.arg_types[3]) \ }; \ ffi_call(&(ctx)->cif, FFI_FN((fn)), (retval), ffiValues); \ } while (0) # define ffi_call5(ctx, fn, retval, arg1, arg2, arg3, arg4, arg5) do { \ void* ffiValues[] = { \ ARGPTR(&arg1, (ctx)->cif.arg_types[0]), \ ARGPTR(&arg2, (ctx)->cif.arg_types[1]), \ ARGPTR(&arg3, (ctx)->cif.arg_types[2]), \ ARGPTR(&arg4, (ctx)->cif.arg_types[3]), \ ARGPTR(&arg5, (ctx)->cif.arg_types[4]) \ }; \ ffi_call(&(ctx)->cif, FFI_FN((fn)), (retval), ffiValues); \ } while (0) # define ffi_call6(ctx, fn, retval, arg1, arg2, arg3, arg4, arg5, arg6) do { \ void* ffiValues[] = { \ ARGPTR(&arg1, (ctx)->cif.arg_types[0]), \ ARGPTR(&arg2, (ctx)->cif.arg_types[1]), \ ARGPTR(&arg3, (ctx)->cif.arg_types[2]), \ ARGPTR(&arg4, (ctx)->cif.arg_types[3]), \ ARGPTR(&arg5, (ctx)->cif.arg_types[4]), \ ARGPTR(&arg6, (ctx)->cif.arg_types[5]) \ }; \ ffi_call(&(ctx)->cif, FFI_FN((fn)), (retval), ffiValues); \ } while (0) #ifdef __cplusplus } #endif #endif /* jffi_jffi_h */ jffi-1.0.2/jni/jffi/Function.h0000644000175000017500000000061711424636215016032 0ustar twernertwerner#ifndef FUNCTION_H #define FUNCTION_H #include #include typedef struct Function { ffi_cif cif; int rawParameterSize; ffi_type** ffiParamTypes; int* rawParamOffsets; bool saveErrno; void* function; } Function; #define SAVE_ERRNO(ctx) do { \ if (unlikely(ctx->saveErrno)) { \ jffi_save_errno(); \ } \ } while(0) #endif /* FUNCTION_H */ jffi-1.0.2/jni/jffi/CallContext.h0000644000175000017500000000051011424636215016455 0ustar twernertwerner#ifndef JFFI_CALLCONTEXT_H #define JFFI_CALLCONTEXT_H #include typedef struct CallContext { /** IMPORTANT: keep ffi_cif as the first field */ ffi_cif cif; int rawParameterSize; ffi_type** ffiParamTypes; int* rawParamOffsets; bool saveErrno; } CallContext; #endif /* JFFI_CALLCONTEXT_H */ jffi-1.0.2/jni/jffi/LastError.h0000644000175000017500000000021411424636215016153 0ustar twernertwerner#ifndef JFFI_LASTERRROR_H #define JFFI_LASTERRROR_H #include "jffi.h" extern void jffi_save_errno(void); #endif /* JFFI_LASTERRROR_H */ jffi-1.0.2/jni/jffi/deprecated.c0000644000175000017500000000106611424636215016337 0ustar twernertwerner#include #include #include #include #include #include #include #include "jffi.h" #include "com_kenai_jffi_Foreign.h" /* * This version of getZeroTerminatedByteArray is deprecated and only here for * binary backwards compatibility. */ JNIEXPORT jbyteArray JNICALL Java_com_kenai_jffi_Foreign_getZeroTerminatedByteArray__JJ(JNIEnv* env, jobject self, jlong address, jlong maxlen) { return Java_com_kenai_jffi_Foreign_getZeroTerminatedByteArray__JI(env, self, address, (jint) maxlen); } jffi-1.0.2/jni/jffi/endian.h0000644000175000017500000000156511424636215015506 0ustar twernertwerner#ifndef JFFI_ENDIAN_H #define JFFI_ENDIAN_H #include #include #ifdef __linux__ # include_next #endif #ifdef __sun # include # define LITTLE_ENDIAN 1234 # define BIG_ENDIAN 4321 # if defined(_BIG_ENDIAN) # define BYTE_ORDER BIG_ENDIAN # elif defined(_LITTLE_ENDIAN) # define BYTE_ORDER LITTLE_ENDIAN # else # error "Cannot determine endian-ness" # endif #endif #if defined(_AIX) && !defined(BYTE_ORDER) # define LITTLE_ENDIAN 1234 # define BIG_ENDIAN 4321 # if defined(__BIG_ENDIAN__) # define BYTE_ORDER BIG_ENDIAN # elif defined(__LITTLE_ENDIAN__) # define BYTE_ORDER LITTLE_ENDIAN # else # error "Cannot determine endian-ness" # endif #endif #if !defined(BYTE_ORDER) || !defined(LITTLE_ENDIAN) || !defined(BIG_ENDIAN) # error "Cannot determine the endian-ness of this platform" #endif #endif /* JFFI_ENDIAN_H */ jffi-1.0.2/jni/jffi/Exception.c0000644000175000017500000000324311424636215016174 0ustar twernertwerner/* * Copyright (C) 2008 Wayne Meissner * * This file is part of jffi. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see . */ #include #include #include #include "Exception.h" void jffi_throwExceptionByName(JNIEnv* env, const char* exceptionName, const char* fmt, ...) { va_list ap; char buf[1024] = { 0 }; va_start(ap, fmt); vsnprintf(buf, sizeof(buf) - 1, fmt, ap); (*env)->PushLocalFrame(env, 10); jclass exceptionClass = (*env)->FindClass(env, exceptionName); if (exceptionClass != NULL) { (*env)->ThrowNew(env, exceptionClass, buf); } (*env)->PopLocalFrame(env, NULL); va_end(ap); } const char* jffi_IllegalArgumentException = "java/lang/IllegalArgumentException"; const char* jffi_NullPointerException = "java/lang/NullPointerException"; const char* jffi_OutOfBoundsException = "java/lang/IndexOutOfBoundsException"; const char* jffi_OutOfMemoryException = "java/lang/OutOfMemoryError"; const char* jffi_RuntimeException = "java/lang/RuntimeError"; const char* jffi_UnsatisfiedLinkException = "java/lang/UnsatisfiedLinkError"; jffi-1.0.2/jni/win32/0000755000175000017500000000000011424636215014114 5ustar twernertwernerjffi-1.0.2/jni/GNUmakefile0000755000175000017500000002111511424636215015227 0ustar twernertwerner# -*- makefile -*- BUILD_OS := $(strip $(shell uname -s | tr '[:upper:]' '[:lower:]')) OS ?= $(BUILD_OS) ifeq ($(OS),sunos) OS = solaris endif # Default value of $OS on Windows is Windows_NT ifeq ($(OS), Windows_NT) # that's how we detect x64... ifneq ($(findstring 64, $(BUILD_OS)),) OS = win64 else OS = win32 endif endif ifneq ($(findstring cygwin, $(BUILD_OS)),) # cygwin is always x32 OS = win32 endif CPU ?= $(shell uname -m | sed -e 's/i[345678]86/i386/') MODEL = 32 # Default to 32bit compiles PLATFORM = $(CPU)-$(OS) JDK_HOME=$(shell if [ -d "$(JAVA_HOME)"/include ];then echo "$(JAVA_HOME)"; else echo "$(JAVA_HOME)"/..; fi) # Set defaults to unix (linux/solaris/bsd) PREFIX = lib JNIEXT = so export MACOSX_DEPLOYMENT_TARGET=10.4 CCACHE := $(strip $(realpath $(shell which ccache 2> /dev/null))) SRC_DIR ?= $(shell pwd)/jni JNI_DIR ?= $(SRC_DIR) BUILD_DIR ?= $(shell pwd)/build JFFI_SRC_DIR = $(SRC_DIR)/jffi JFFI_BUILD_DIR = $(BUILD_DIR)/jffi ifeq ($(USE_SYSTEM_LIBFFI),1) LIBFFI_LIBS ?= $(shell pkg-config --libs libffi) LIBFFI_CFLAGS ?= $(shell pkg-config --cflags libffi) else LIBFFI_SRC_DIR = $(SRC_DIR)/libffi LIBFFI_BUILD_DIR = $(BUILD_DIR)/libffi-$(PLATFORM) LIBFFI = $(LIBFFI_BUILD_DIR)/.libs/libffi_convenience.a LIBFFI_LIBS = $(LIBFFI) LIBFFI_CFLAGS = -I"$(LIBFFI_BUILD_DIR)"/include endif SRCS = $(wildcard $(JFFI_SRC_DIR)/*.c) OBJS = $(patsubst %.c, $(JFFI_BUILD_DIR)/%.o, $(notdir $(SRCS))) vpath %.h $(JFFI_SRC_DIR) LIBNAME = jffi # # Compiler/linker flags from: # http://weblogs.java.net/blog/kellyohair/archive/2006/01/compilation_of_1.html JFLAGS = -fno-omit-frame-pointer -fno-strict-aliasing -DNDEBUG OFLAGS = -O2 $(JFLAGS) # MacOS headers aren't completely warning free, so turn them off ifneq ($(OS),darwin) WFLAGS += -Wundef -Werror endif WFLAGS += -W -Wall -Wno-unused -Wno-parentheses PICFLAGS = -fPIC SOFLAGS = # Filled in for each OS specifically FFI_MMAP_EXEC = -DFFI_MMAP_EXEC_WRIT FFI_CC = $(CCACHE) $(CC) FFI_LD = $(LD) FFI_CFLAGS = $(FFI_MMAP_EXEC) $(OFLAGS) STRIP ?= strip -S JDK_INCLUDES = -I"$(JDK_HOME)/include" -I"$(JDK_HOME)/include/$(OS)" IFLAGS = -I"$(BUILD_DIR)" -I"$(BUILD_DIR)"/jni -I$(SRC_DIR) -I"$(JFFI_SRC_DIR)" CFLAGS = $(OFLAGS) $(WFLAGS) $(IFLAGS) $(PICFLAGS) $(JDK_INCLUDES) $(LIBFFI_CFLAGS) CFLAGS += -D_REENTRANT -D_LARGEFILE64_SOURCE -D_GNU_SOURCE ifeq ($(OS), win64) override CPU = x86_64 JDK_INCLUDES=-I$(JNI_DIR)/win32/include -I$(JNI_DIR)/win32/include/win32 CC = x86_64-w64-mingw32-gcc -m64 PICFLAGS = ifneq ($(findstring cygwin, $(BUILD_OS)),) CC += -mno-cygwin LDFLAGS += -mno-cygwin endif CFLAGS += -mwin32 -D_JNI_IMPLEMENTATION_ LDFLAGS += -Wl,--add-stdcall-alias PICFLAGS= SOFLAGS += -shared -mimpure-text -static-libgcc PREFIX = JNIEXT=dll AR = x86_64-w64-mingw32-ar LD = x86_64-w64-mingw32-ld STRIP = x86_64-w64-mingw32-strip --strip-debug CONFIGURE_BUILD = x86_64-w64-mingw32 endif ifeq ($(OS),cross-mingw32) override OS = win32 override CPU = i386 JDK_INCLUDES=-I$(JNI_DIR)/win32/include -I$(JNI_DIR)/win32/include/win32 CC = i386-mingw32-gcc LD = i386-mingw32-ld STRIP = i386-mingw32-strip --strip-debug CONFIGURE_HOST = i386-mingw32 endif ifneq ($(findstring cygwin,$(BUILD_OS)),) OS = win32 JAVA_HOME := $(shell cygpath -u $(JAVA_HOME)) endif ifeq ($(OS), win32) ifneq ($(findstring cygwin, $(BUILD_OS)),) CC += -mno-cygwin LDFLAGS += -mno-cygwin endif CFLAGS += -mwin32 -D_JNI_IMPLEMENTATION_ # Linking against CRTMT.O is a workaround for GCC 4.4 bug # that ignores __thread (which we really need for errno handling). # See: http://n2.nabble.com/gcc-4-4-multi-threaded-exception-handling-thread-specifier-not-working-td3440749.html CRTMT.O = $(shell $(CC) -print-file-name=crtmt.o) LDFLAGS += -Wl,--add-stdcall-alias $(CRTMT.O) PICFLAGS= SOFLAGS += -shared -mimpure-text -static-libgcc PREFIX = JNIEXT=dll endif ifeq ($(OS), darwin) PLATFORM = darwin ARCHES = ppc ifneq ($(findstring $(CPU), i386 x86_64),) ARCHES = i386 x86_64 endif CC = gcc-4.0 MACSDK = /Developer/SDKs/MacOSX10.4u.sdk CFLAGS += -isysroot $(MACSDK) -DTARGET_RT_MAC_CFM=0 CFLAGS += $(foreach arch, $(ARCHES),-arch $(arch)) LDFLAGS = $(foreach arch, $(ARCHES),-arch $(arch)) -dynamiclib -framework JavaVM \ -Wl,-syslibroot,$(MACSDK) -mmacosx-version-min=10.4 JNIEXT = jnilib #CFLAGS += -I$(MACSDK)/System/Library/Frameworks/Kernel.framework/Versions/A/Headers FFI_CFLAGS += -isysroot $(MACSDK) PICFLAGS = SOFLAGS = endif ifeq ($(OS), linux) SOFLAGS = -shared -mimpure-text -static-libgcc -Wl,-soname,$(@F) -Wl,-O1 CFLAGS += -pthread endif ifeq ($(OS), solaris) CC = gcc CFLAGS += -D__EXTENSIONS__ -std=c99 LD = /usr/ccs/bin/ld SOFLAGS = -shared -static-libgcc -mimpure-text LIBS += -ldl STRIP = strip endif ifeq ($(OS), aix) SOFLAGS = -shared -static-libgcc CFLAGS += -pthread LDFLAGS += -pthread JNIEXT = a STRIP = strip endif ifneq ($(findstring bsd, $(OS)),) SOFLAGS = -shared -static-libgcc CFLAGS += -pthread LDFLAGS += -pthread endif ifeq ($(CPU), i386) ifneq ($(findstring $(OS), linux),) CFLAGS += -march=i586 -mtune=generic endif endif ifneq ($(findstring $(CPU), x86_64 amd64 sparcv9 ppc64 powerpc64 s390x),) MODEL = 64 endif # On platforms (linux, solaris) that support both 32bit and 64bit, force building for one or the other ifneq ($(strip $(findstring $(OS), linux solaris)),) # Change the CC/LD instead of CFLAGS/LDFLAGS, incase other things in the flags # makes the libffi build choke CC += -m$(MODEL) LD += -m$(MODEL) endif LIBJFFI = $(BUILD_DIR)/$(PREFIX)$(LIBNAME)-$(VERSION).$(JNIEXT) LIBFFI_CONFIGURE = $(LIBFFI_SRC_DIR)/configure --disable-static \ --with-pic=yes --disable-dependency-tracking ifdef CONFIGURE_HOST LIBFFI_CONFIGURE += --host=$(CONFIGURE_HOST) endif ifdef CONFIGURE_BUILD LIBFFI_CONFIGURE += --build=$(CONFIGURE_BUILD) endif all: $(LIBJFFI) debug: @echo OS="$(OS)" @echo BUILD_OS="$(BUILD_OS)" @echo CPU="$(CPU)" @echo JAVA_HOME="$(JAVA_HOME)" @echo JDK_HOME="$(JDK_HOME)" @echo "PLATFORM=$(PLATFORM)" @echo "JFFI_BUILD_DIR=$(JFFI_BUILD_DIR)" @echo "OBJS=$(OBJS)" $(LIBJFFI): $(OBJS) $(LIBFFI_LIBS) $(CC) -o $@ $(LDFLAGS) $(SOFLAGS) $(OBJS) $(LIBFFI_LIBS) $(LIBS) $(STRIP) $@ # For the primitive int interface, don't do frame pointer save/restore $(JFFI_BUILD_DIR)/Fast%Invoke.o : $(JFFI_SRC_DIR)/Fast%Invoke.c $(wildcard $(JFFI_SRC_DIR)/*.h) $(LIBFFI) @mkdir -p $(@D) @$(CCACHE) $(CC) $(CFLAGS) -fomit-frame-pointer -c $< -o $@ $(BUILD_DIR)/%.o : $(SRC_DIR)/%.c $(wildcard $(JFFI_SRC_DIR)/*.h) @mkdir -p $(@D) @$(CCACHE) $(CC) $(CFLAGS) -c $< -o $@ $(OBJS) : $(LIBFFI_LIBS) ifeq ($(OS), darwin) build_ffi = \ mkdir -p $(BUILD_DIR)/libffi-darwin-$(1); \ (if [ ! -f $(BUILD_DIR)/libffi-darwin-$(1)/Makefile ]; then \ echo "Configuring libffi for $(1)"; \ cd $(BUILD_DIR)/libffi-darwin-$(1) && \ env CC="$(CCACHE) $(CC)" CFLAGS="-arch $(1) $(FFI_CFLAGS)" LDFLAGS="-arch $(1)" \ $(LIBFFI_CONFIGURE) --host=$(1)-apple-darwin > /dev/null; \ fi); \ env MACOSX_DEPLOYMENT_TARGET=10.4 $(MAKE) -C $(BUILD_DIR)/libffi-darwin-$(1) $(LIBFFI): @mkdir -p $(@D) @for arch in $(ARCHES); do $(call build_ffi,$$arch);done # Assemble into a FAT (i386, x86_64, ppc) library @mkdir -p $(BUILD_DIR)/libffi/.libs @env MACOSX_DEPLOYMENT_TARGET=10.4 /usr/bin/libtool -static -o $@ \ $(foreach arch, $(ARCHES),$(BUILD_DIR)/libffi-darwin-$(arch)/.libs/libffi_convenience.a) @mkdir -p $(LIBFFI_BUILD_DIR)/include $(RM) $(LIBFFI_BUILD_DIR)/include/ffi.h @( \ printf "#if defined(__i386__)\n"; \ printf "#include \"libffi-darwin-i386/include/ffi.h\"\n"; \ printf "#elif defined(__x86_64__)\n"; \ printf "#include \"libffi-darwin-x86_64/include/ffi.h\"\n";\ printf "#elif defined(__ppc__)\n"; \ printf "#include \"libffi-darwin-ppc/include/ffi.h\"\n";\ printf "#endif\n";\ ) > $(LIBFFI_BUILD_DIR)/include/ffi.h @( \ printf "#if defined(__i386__)\n"; \ printf "#include \"libffi-darwin-i386/include/ffitarget.h\"\n"; \ printf "#elif defined(__x86_64__)\n"; \ printf "#include \"libffi-darwin-x86_64/include/ffitarget.h\"\n";\ printf "#elif defined(__ppc__)\n"; \ printf "#include \"libffi-darwin-ppc/include/ffitarget.h\"\n";\ printf "#endif\n";\ ) > $(LIBFFI_BUILD_DIR)/include/ffitarget.h else $(LIBFFI): @mkdir -p $(LIBFFI_BUILD_DIR) @if [ ! -f $(LIBFFI_BUILD_DIR)/Makefile ]; then \ echo "Configuring libffi for $(PLATFORM)"; \ cd $(LIBFFI_BUILD_DIR) && env CC="$(FFI_CC)" LD="$(FFI_LD)" CFLAGS="$(FFI_CFLAGS)" \ $(LIBFFI_CONFIGURE) > /dev/null; \ fi $(MAKE) -C $(LIBFFI_BUILD_DIR) endif clean:: # nothing to do - ant will delete the build dir jffi-1.0.2/jni/libffi/0000755000175000017500000000000011424636215014405 5ustar twernertwerner