[jffi-next] 15/22: Import CallContext and caching from default branch
Tim Potter
tpot-guest at moszumanska.debian.org
Wed Mar 4 04:51:23 UTC 2015
This is an automated email from the git hooks/post-receive script.
tpot-guest pushed a commit to tag 0.6.0.1
in repository jffi-next.
commit 9bcee4b445eb864a7b11a20c4610b400e3b67d8c
Author: Wayne Meissner <wmeissner at gmail.com>
Date: Tue Oct 13 18:55:16 2009 +1000
Import CallContext and caching from default branch
---
src/com/kenai/jffi/CallContext.java | 105 +++++++++++++++++
src/com/kenai/jffi/CallContextCache.java | 126 ++++++++++++++++++++
src/com/kenai/jffi/CallInfo.java | 8 ++
src/com/kenai/jffi/Closure.java | 3 +
src/com/kenai/jffi/ClosureManager.java | 176 +++-------------------------
src/com/kenai/jffi/DirectClosureBuffer.java | 145 +++++++++++++++++++++++
6 files changed, 404 insertions(+), 159 deletions(-)
diff --git a/src/com/kenai/jffi/CallContext.java b/src/com/kenai/jffi/CallContext.java
new file mode 100644
index 0000000..c869182
--- /dev/null
+++ b/src/com/kenai/jffi/CallContext.java
@@ -0,0 +1,105 @@
+
+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 return type of this function */
+ private final Type returnType;
+
+ /** The parameter types of this function */
+ private final Type[] parameterTypes;
+
+ final int flags;
+
+ final long nativeReturnType;
+
+ final long[] nativeParameterTypes;
+
+ /**
+ * Creates a new instance of <tt>Function</tt> 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 <tt>Function</tt>.
+ *
+ * <tt>Function</tt> 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 <tt>Function</tt>.
+ *
+ * @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) {
+
+ this.flags = (!saveErrno ? Foreign.F_NOERRNO : 0)
+ | (convention == CallingConvention.STDCALL ? Foreign.F_STDCALL : Foreign.F_DEFAULT);
+
+ //
+ // Keep references to the return and parameter types so they do not get
+ // garbage collected
+ //
+ this.returnType = returnType;
+ this.parameterTypes = (Type[]) paramTypes.clone();
+
+ this.nativeReturnType = returnType.handle();
+ this.nativeParameterTypes = Type.nativeHandles(paramTypes);
+ }
+
+ /**
+ * Gets the number of parameters the native function accepts.
+ *
+ * @return The number of parameters the native function accepts.
+ */
+ public final int getParameterCount() {
+ return parameterTypes.length;
+ }
+
+ /**
+ * 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 <tt>Type</tt> of the parameter.
+ */
+ public final Type getParameterType(int index) {
+ return parameterTypes[index];
+ }
+
+ public synchronized final void dispose() {
+ }
+}
diff --git a/src/com/kenai/jffi/CallContextCache.java b/src/com/kenai/jffi/CallContextCache.java
new file mode 100644
index 0000000..54e825a
--- /dev/null
+++ b/src/com/kenai/jffi/CallContextCache.java
@@ -0,0 +1,126 @@
+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<Signature, CallContextRef> contextCache = new ConcurrentHashMap<Signature, CallContextRef>();
+ private final ReferenceQueue<CallContext> contextReferenceQueue = new ReferenceQueue<CallContext>();
+
+ /** 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 <tt>CallContextCache</tt>
+ *
+ * @return An instance of a <tt>CallContextCache</tt>
+ */
+ 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<CallContext> {
+
+ final Signature signature;
+
+ public CallContextRef(Signature signature, CallContext ctx, ReferenceQueue<CallContext> 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());
+ }
+ }
+}
diff --git a/src/com/kenai/jffi/CallInfo.java b/src/com/kenai/jffi/CallInfo.java
new file mode 100644
index 0000000..2e95647
--- /dev/null
+++ b/src/com/kenai/jffi/CallInfo.java
@@ -0,0 +1,8 @@
+
+package com.kenai.jffi;
+
+public interface CallInfo {
+ int getParameterCount();
+ public Type getReturnType();
+ public Type getParameterType(int parameterIndex);
+}
diff --git a/src/com/kenai/jffi/Closure.java b/src/com/kenai/jffi/Closure.java
index a7c1bbb..5681cc0 100644
--- a/src/com/kenai/jffi/Closure.java
+++ b/src/com/kenai/jffi/Closure.java
@@ -174,6 +174,9 @@ public interface Closure {
* time, and is non-deterministic. This allows explicit control over
* memory reclamation.
*/
+ void dispose();
+
+ @Deprecated
void free();
}
}
diff --git a/src/com/kenai/jffi/ClosureManager.java b/src/com/kenai/jffi/ClosureManager.java
index eda39c6..94fde50 100644
--- a/src/com/kenai/jffi/ClosureManager.java
+++ b/src/com/kenai/jffi/ClosureManager.java
@@ -8,7 +8,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
* Allocates and manages the lifecycle of native closures (aka callbacks).rm hs
*/
public class ClosureManager {
- private static final long ADDRESS_MASK = Platform.getPlatform().addressMask();
private static final Object lock = new Object();
/** Holder class to do lazy allocation of the ClosureManager instance */
@@ -39,18 +38,22 @@ public class ClosureManager {
* @return A new {@link Closure.Handle} instance.
*/
public final Closure.Handle newClosure(Closure closure, Type returnType, Type[] parameterTypes, CallingConvention convention) {
- Proxy proxy = new Proxy(closure, returnType, parameterTypes);
+ return newClosure(closure, CallContextCache.getInstance().getCallContext(returnType, parameterTypes, convention));
+ }
+
+ public final Closure.Handle newClosure(Closure closure, CallContext ctx) {
+ Proxy proxy = new Proxy(closure, ctx);
long handle = 0;
synchronized (lock) {
handle = Foreign.getInstance().newClosure(proxy, Proxy.METHOD,
- returnType.handle(), Type.nativeHandles(parameterTypes), 0);
+ ctx.nativeReturnType, ctx.nativeParameterTypes, ctx.flags);
}
if (handle == 0) {
throw new RuntimeException("Failed to create native closure");
}
- return new Handle(handle, returnType, parameterTypes);
+ return new Handle(handle, ctx);
}
/**
@@ -80,19 +83,17 @@ public class ClosureManager {
* 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 CallContext ctx;
/**
* Creates a new Handle to lifecycle manager the native closure.
*
* @param handle The address of the native closure structure.
*/
- Handle(long handle, Type returnType, Type[] parameterTypes) {
+ Handle(long handle, CallContext ctx) {
this.handle = handle;
cbAddress = IO.getAddress(handle);
- this.returnType = returnType;
- this.parameterTypes = (Type[]) parameterTypes.clone();
+ this.ctx = ctx;
}
public long getAddress() {
@@ -103,7 +104,9 @@ public class ClosureManager {
this.autorelease = autorelease;
}
- public void free() {
+ public void free() { dispose(); }
+
+ public void dispose() {
if (released.getAndSet(true)) {
throw new IllegalStateException("Closure already released");
}
@@ -140,8 +143,7 @@ public class ClosureManager {
* Keep references to the return and parameter types so they do not get
* garbage collected until the closure does.
*/
- final Type returnType;
- final Type[] parameterTypes;
+ final CallContext ctx;
/**
* Gets the
@@ -162,10 +164,9 @@ public class ClosureManager {
* @param returnType The native return type of the closure
* @param parameterTypes The parameterTypes of the closure
*/
- Proxy(Closure closure, Type returnType, Type[] parameterTypes) {
+ Proxy(Closure closure, CallContext ctx) {
this.closure = closure;
- this.returnType = returnType;
- this.parameterTypes = (Type[]) parameterTypes.clone();
+ this.ctx = ctx;
}
/**
@@ -176,150 +177,7 @@ public class ClosureManager {
* @param paramAddress The address of the native parameter buffer.
*/
void invoke(long retvalAddress, long paramAddress) {
- closure.invoke(new DirectBuffer(returnType, parameterTypes, retvalAddress, paramAddress));
- }
- }
-
- /**
- * Implementation of the {@link Closure.Buffer} interface to read/write
- * parameter and return value data in native memory
- */
- private static final class DirectBuffer implements Closure.Buffer {
- private static final com.kenai.jffi.MemoryIO IO = com.kenai.jffi.MemoryIO.getInstance();
- private static final NativeWordIO WordIO = NativeWordIO.getInstance();
- private static final int PARAM_SIZE = Platform.getPlatform().addressSize() / 8;
- private final long retval, parameters;
-
- /* Keep references to the return and parameter types to prevent garbage collection */
- private final Type returnType;
- private final Type[] parameterTypes;
-
- public DirectBuffer(Type returnType, Type[] parameterTypes, long retval, long parameters) {
- this.returnType = returnType;
- this.parameterTypes = parameterTypes;
- 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))) & ADDRESS_MASK;
- }
-
- 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, returnType.size());
- }
-
- public void setStructReturn(byte[] data, int offset) {
- IO.putByteArray(retval, data, offset, returnType.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);
+ closure.invoke(new DirectClosureBuffer(ctx, retvalAddress, paramAddress));
}
}
}
diff --git a/src/com/kenai/jffi/DirectClosureBuffer.java b/src/com/kenai/jffi/DirectClosureBuffer.java
new file mode 100644
index 0000000..4c13527
--- /dev/null
+++ b/src/com/kenai/jffi/DirectClosureBuffer.java
@@ -0,0 +1,145 @@
+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 long ADDRESS_MASK = Platform.getPlatform().addressMask();
+ private static final NativeWordIO WordIO = NativeWordIO.getInstance();
+ private static final int 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))) & ADDRESS_MASK;
+ }
+
+ 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);
+ }
+ }
+}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/jffi-next.git
More information about the pkg-java-commits
mailing list