diff --git a/CHANGES.md b/CHANGES.md index 36b5da3bc0..af9e8a4533 100755 --- a/CHANGES.md +++ b/CHANGES.md @@ -24,6 +24,7 @@ Features * [#350](https://github.com/twall/jna/pull/350): Added `jnacontrib.x11.api.X.Window.getSubwindows` - [@rm5248](https://github.com/rm5248). * Improved `contrib/msoffice` sample - [@wolftobias](https://github.com/wolftobias). * [#352](https://github.com/twall/jna/pull/352): Performance improvements due to reduced locking in `com.sun.jna.Library$Handler` and fewer vararg checks in `com.sun.jna.Function` - [@Boereck](https://github.com/Boereck). +* [#353](https://github.com/twall/jna/pull/353): Performance improvements by improved collaboration between `com.sun.jna.Library$Handler` and `com.sun.jna.Function` - [@Boereck](https://github.com/Boereck). * [#357](https://github.com/twall/jna/pull/357): Added `com.sun.jna.platform.win32.Kernel32.SetSystemTime` - [@lgoldstein](https://github.com/lgoldstein), [@thomasjoulin](https://github.com/thomasjoulin). * [#365](https://github.com/twall/jna/pull/365): Added `com.sun.jna.platform.win32.Kernel32.GetComputerNameEx` support - [@lgoldstein](https://github.com/lgoldstein). * [#368](https://github.com/twall/jna/pull/368): Added `com.sun.jna.platform.win32.Kernel32.VirtualQueryEx`, `com.sun.jna.platform.win32.WinNT.MEMORY_BASIC_INFORMATION` and `MEM_COMMIT`, `MEM_FREE`, `MEM_RESERVE`, `MEM_IMAGE`, `MEM_MAPPED`, `MEM_PRIVATE` constants - [@apsk](https://github.com/apsk). diff --git a/src/com/sun/jna/Function.java b/src/com/sun/jna/Function.java index 7bcc68c973..6a58e4d185 100644 --- a/src/com/sun/jna/Function.java +++ b/src/com/sun/jna/Function.java @@ -272,6 +272,17 @@ public Object invoke(Class returnType, Object[] inArgs) { * native result as an Object. */ public Object invoke(Class returnType, Object[] inArgs, Map options) { + Method invokingMethod = (Method)options.get(OPTION_INVOKING_METHOD); + Class[] paramTypes = invokingMethod != null ? invokingMethod.getParameterTypes() : null; + return invoke(invokingMethod, paramTypes, returnType, inArgs, options); + } + + /** Invoke the native function with the given arguments, returning the + * native result as an Object. This method can be called if invoking method and parameter + * types are already at hand. When calling {@link Function#invoke(Class, Object[], Map)}, + * the method has to be in the options under key {@link Function#OPTION_INVOKING_METHOD}. + */ + Object invoke(Method invokingMethod, Class[] paramTypes, Class returnType, Object[] inArgs, Map options) { // Clone the argument array to obtain a scratch space for modified // types/values Object[] args = { }; @@ -285,8 +296,6 @@ public Object invoke(Class returnType, Object[] inArgs, Map options) { TypeMapper mapper = (TypeMapper)options.get(Library.OPTION_TYPE_MAPPER); - Method invokingMethod = (Method)options.get(OPTION_INVOKING_METHOD); - Class[] paramTypes = invokingMethod != null ? invokingMethod.getParameterTypes() : null; boolean allowObjects = Boolean.TRUE.equals(options.get(Library.OPTION_ALLOW_OBJECTS)); boolean isVarArgs = args.length > 0 && invokingMethod != null ? isVarArgs(invokingMethod) : false; for (int i=0; i < args.length; i++) { diff --git a/src/com/sun/jna/Library.java b/src/com/sun/jna/Library.java index e4d0f5d5fc..4d9e53c3d9 100644 --- a/src/com/sun/jna/Library.java +++ b/src/com/sun/jna/Library.java @@ -167,18 +167,20 @@ public Class getInterfaceClass() { */ private static final class FunctionInfo { - FunctionInfo(InvocationHandler handler, Function function, boolean isVarArgs, Map options) { + FunctionInfo(InvocationHandler handler, Function function, Class[] parameterTypes, boolean isVarArgs, Map options) { super(); this.handler = handler; this.function = function; this.isVarArgs = isVarArgs; this.options = options; + this.parameterTypes = parameterTypes; } final InvocationHandler handler; final Function function; final boolean isVarArgs; final Map options; + final Class[] parameterTypes; } public Object invoke(Object proxy, Method method, Object[] inArgs) @@ -211,14 +213,16 @@ else if (OBJECT_EQUALS.equals(method)) { handler = invocationMapper.getInvocationHandler(nativeLibrary, method); } Function function = null; + Class[] parameterTypes = null; Map options = null; if (handler == null) { // Find the function to invoke function = nativeLibrary.getFunction(method.getName(), method); + parameterTypes = method.getParameterTypes(); options = new HashMap(this.options); options.put(Function.OPTION_INVOKING_METHOD, method); } - f = new FunctionInfo(handler, function, isVarArgs, options); + f = new FunctionInfo(handler, function, parameterTypes, isVarArgs, options); functions.put(method, f); } } @@ -229,7 +233,7 @@ else if (OBJECT_EQUALS.equals(method)) { if (f.handler != null) { return f.handler.invoke(proxy, method, inArgs); } - return f.function.invoke(method.getReturnType(), inArgs, f.options); + return f.function.invoke(method, f.parameterTypes, method.getReturnType(), inArgs, f.options); } } }