[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