Comparar commits
107 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| d42863603e | |||
| 2c19cf3e31 | |||
| e7dc918c6a | |||
| 64c9e8212a | |||
| 499c39f13d | |||
| bccdae735b | |||
| 58120730a5 | |||
| 5b8db8a680 | |||
| 0acfd583c8 | |||
| 402b7ef67e | |||
| 6944871c42 | |||
| b60da35689 | |||
| 5204feddb1 | |||
| 68156df66b | |||
| a9e8b27285 | |||
| b8f470ddbd | |||
| 9d075dd1d1 | |||
| 4b802c6f60 | |||
| 8ce9344dd0 | |||
| cb2b386791 | |||
| 7ee4681c10 | |||
| 82c0ea9df2 | |||
| 9070d80880 | |||
| 45c53caf94 | |||
| c4947618c1 | |||
| 941ed59c37 | |||
| d76bbec1ab | |||
| f5a1d98cf9 | |||
| b0e6d837f0 | |||
| b1cfb1b733 | |||
| 26a1212546 | |||
| 03b05aaae9 | |||
| f41c87d7c9 | |||
| b74deb5e35 | |||
| 240e2db637 | |||
| 441947b6a4 | |||
| 194bdaffcd | |||
| db6e9ff4c6 | |||
| 57261a1164 | |||
| 0b116bb409 | |||
| a5ad2e5de2 | |||
| b6928ff6c0 | |||
| 4b03dd321c | |||
| f7eefbd3d7 | |||
| b23f7f9b27 | |||
| b95bc7e4c4 | |||
| 1593c0c347 | |||
| c154663455 | |||
| 13bc1901dc | |||
| 4f28322ac2 | |||
| 756e2ced8b | |||
| 1dc78b5209 | |||
| 3464093273 | |||
| 4487214494 | |||
| 6d7e222946 | |||
| d12a6a3178 | |||
| ed9d609c35 | |||
| b86f359d93 | |||
| 02080dfcf8 | |||
| 2768d25884 | |||
| 7bdf9896d2 | |||
| 3b4f84ded8 | |||
| 69abc52731 | |||
| 1671b1fb8b | |||
| 8735f4ef5c | |||
| 86967b5786 | |||
| ca8ceeb130 | |||
| 41d6f8eeea | |||
| 27b7805608 | |||
| fef39f7013 | |||
| b414b54c6b | |||
| ccdbb20ad0 | |||
| eb7e47bf29 | |||
| 53988c7184 | |||
| 9092b2bdc5 | |||
| 068353aa5b | |||
| 95a17ddbf0 | |||
| 6c8c455f5b | |||
| 282032e178 | |||
| af63e6a80d | |||
| a46ba0da29 | |||
| f7738bf65b | |||
| bb11d1fe37 | |||
| d02a2deb52 | |||
| 46105d849d | |||
| f16b6c3482 | |||
| a9cb497045 | |||
| d529a34ecb | |||
| 5394029dc5 | |||
| 28247737ca | |||
| 6448c2d8fb | |||
| 4460ccc8ec | |||
| 2b02a3c533 | |||
| 6705513b86 | |||
| 4bd8d12481 | |||
| ccaf3c283b | |||
| ce4276a0cb | |||
| 709e316e56 | |||
| e46635d6ab | |||
| 0af8677ba4 | |||
| 9ab13daf09 | |||
| 17977fbabc | |||
| 83854047b7 | |||
| 28e56fd587 | |||
| 29fc6308b8 | |||
| 14a7df128d | |||
| dd4ef89d0a |
+8
-8
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" output="build.eclipse/test-classes" path="test"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JDK 1.5"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
|
||||
<classpathentry kind="output" path="build.eclipse/classes"/>
|
||||
</classpath>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" output="build.eclipse/test-classes" path="test"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
|
||||
<classpathentry kind="output" path="build.eclipse/classes"/>
|
||||
</classpath>
|
||||
|
||||
+54
-46
@@ -22,7 +22,22 @@
|
||||
|
||||
# TODO
|
||||
|
||||
* make native dll extraction from jar public
|
||||
* make direct calls call back *once* to Java where conversion is required,
|
||||
and process all arguments from there (instead of potentially swapping back
|
||||
and forth multipel times). This also makes it easer to perform conversions
|
||||
(no native changes required).
|
||||
|
||||
* direct/raw non-primitive array arguments (String[], Pointer[], NativeMapped[])
|
||||
|
||||
* ppc64 direct/raw failures (multiple)
|
||||
|
||||
* direct calls on ppc to varargs (callbacks) with FP args fail; avoid them for
|
||||
now
|
||||
|
||||
* combine direct and interface mapping calling code where possible
|
||||
|
||||
* make native dll extraction from jar public, to use with user dlls packaged
|
||||
in a jar
|
||||
|
||||
* Callback.PostCallWrite.write() cf PostCallRead; do Structure.write for any
|
||||
arguments as well
|
||||
@@ -38,28 +53,7 @@
|
||||
|
||||
Requires separate compilation of annotation handling.
|
||||
|
||||
* parser (gluegen? swig? others?) to auto-generate JNA interfaces from headers;
|
||||
ideally get the native library build system to output preprocessed headers,
|
||||
otherwise CPP crap is a nightmare to get right.
|
||||
o write SWIG transformer to auto-generate interfaces from header files
|
||||
o see JNAerator
|
||||
|
||||
* should structure offsets be 64-bit? technically yes, but in practice I don't
|
||||
think a structure that big actually works.
|
||||
|
||||
* (maybe) move all native functions into Native (limit header files, easier
|
||||
management)
|
||||
|
||||
* Does it make sense to define Int16/UInt16, Int32/UInt32, etc? Probably not
|
||||
the signed versions, but maybe the unsigned ones, to facilitate generating
|
||||
unsigned values (maybe just provide utilities to pack an unsigned int into a
|
||||
signed int). What about size_t, off_t, et al.? Would either need a
|
||||
bunch of native lookup functions (more accurate) or java-side conditionals
|
||||
(less robust but easier to change).
|
||||
o bounds checking is handled by IntegerType (pass in a long, get an
|
||||
exception if the value is out of bounds).
|
||||
o when used as struct fields, could allow detection of field order by order
|
||||
of initialization (requires all-or-nothing usage, though)
|
||||
* ditch type conversion context.
|
||||
|
||||
* packaging: 'types', 'convert/marshal' subpackages?
|
||||
note: marshal/unmarshal vs to/fromnative: to/fromnative is more
|
||||
@@ -69,12 +63,6 @@
|
||||
Pointer into a types subpackage (which would leave just a few top-level
|
||||
classes). Javadoc is cluttered by example classes anyway.
|
||||
|
||||
* Make a separate jar file for all OS-specific headers
|
||||
Maybe make interfaces per-header file (winbase, winnt, stdlib, etc),
|
||||
aggregated per-library (interface CLibrary extends stdlib, stdio, etc)
|
||||
(how useful would it really be, or is this just sorting legos?)
|
||||
o same for windowutils, fileutils, etc.
|
||||
|
||||
* support annotations of parameters and return values w/o breaking
|
||||
1.4 compatibility (retroweaver?), e.g.
|
||||
-- retroweaver (requires retroweaver runtime classes to provide annotation
|
||||
@@ -89,14 +77,6 @@
|
||||
this only really applies to NativeLong/IntegerType types that want to use a
|
||||
primitive value instead of creating an object instance.
|
||||
|
||||
* Allow Buffer in Structures (and callbacks) (auto-wrap in direct byte buffer)?
|
||||
o this gets tricky when reading structs from native memory; we don't know if
|
||||
the value is already mapped to a buffer (cf CallbackReference)
|
||||
|
||||
* standard types for various platforms: posix/types.h, w32 (DWORD, HANDLE)
|
||||
* StringBuffer/StringBuilder as mutable char*/wchar_t* argument
|
||||
NOTE: byte[]/char[] is probably better; it's trivial to convert to String
|
||||
and native code can't change the size anyway
|
||||
* flag string(/wstring)-returning methods which need to free their result
|
||||
to avoid leaking memory whan auto-creating strings from the result
|
||||
(since normally we don't take explicit ownership of any returned pointers)
|
||||
@@ -113,9 +93,6 @@
|
||||
"pointer-requiring-free" (which is just Memory). For now, leave it up to
|
||||
the user to manage the pointer, since they have to define the free method
|
||||
anyway. use could always put a finalizer on a PointerType-derived type.
|
||||
* provide library load/unload hooks (Runnables in options?). Examples:
|
||||
o GetLastError (no longer needed)
|
||||
o WSAInit?
|
||||
* if method has "GetLastErrorException/ErrnoException" in its signature, use
|
||||
result codes + GetLastError/errno/errstr to auto-generate
|
||||
runtime exceptions? (cf P/Invoke; also useful for X11 return types)
|
||||
@@ -127,21 +104,22 @@
|
||||
if nonzero ?
|
||||
o otherwise, need an ExceptionOnZero, ExceptionOnNonZero runtime, from which
|
||||
derive GetLastError/ErrnoExceptionOnZero/NZ
|
||||
* determine X11 display name from current java program (if any); null is ok
|
||||
since it uses getenv(DISPLAY), which is what java would do
|
||||
note: DISPLAY may be available in GraphicsDevice->getIDstring
|
||||
* universal GCC build w/cross-compile (needs cross compilers...)
|
||||
* return Pointer.SIZE/LONG_SIZE/WCHAR_SIZE in bits (for consistency with 1.5)
|
||||
Long.SIZE, Integer.SIZE, et al.
|
||||
* interface "lvalue", which can provide a pointer to itself (reference() or
|
||||
addressOf())?
|
||||
* verify get/set methods vs read/write for performance (Pointer)?
|
||||
* bitfields for structs (how?)
|
||||
|
||||
|
||||
|
||||
|
||||
# DONE
|
||||
* verify get/set methods vs read/write for performance (Pointer)?
|
||||
(see RawTest for performance comparisons)
|
||||
* Allow Buffer in Structures (and callbacks) (auto-wrap in direct byte buffer)?
|
||||
o this gets tricky when reading structs from native memory; we don't know if
|
||||
the value is already mapped to a buffer (cf CallbackReference)
|
||||
* standard types for various platforms: posix/types.h, w32 (DWORD, HANDLE)
|
||||
|
||||
* embed version in DLL ('depends'-done)/so (symlink?)
|
||||
* use libffi closure allocation/deallocation
|
||||
|
||||
@@ -261,5 +239,35 @@ transient callbacks, and require callback+dispose for most callbacks?
|
||||
void setWindowMask(Window w, Shape clip);
|
||||
// needs:
|
||||
int findNativeWindow(Window w);
|
||||
|
||||
#MAYBE NOT
|
||||
* should structure offsets be 64-bit? technically yes, but in practice I don't
|
||||
think a structure that big actually works.
|
||||
* (maybe) move all native functions into Native (limit header files, easier
|
||||
management)
|
||||
* Does it make sense to define Int16/UInt16, Int32/UInt32, etc? Probably not
|
||||
the signed versions, but maybe the unsigned ones, to facilitate generating
|
||||
unsigned values (maybe just provide utilities to pack an unsigned int into a
|
||||
signed int). What about size_t, off_t, et al.? Would either need a
|
||||
bunch of native lookup functions (more accurate) or java-side conditionals
|
||||
(less robust but easier to change).
|
||||
o bounds checking is handled by IntegerType (pass in a long, get an
|
||||
exception if the value is out of bounds).
|
||||
o when used as struct fields, could allow detection of field order by order
|
||||
of initialization (requires all-or-nothing usage, though)
|
||||
* Make a separate jar file for all OS-specific headers
|
||||
Maybe make interfaces per-header file (winbase, winnt, stdlib, etc),
|
||||
aggregated per-library (interface CLibrary extends stdlib, stdio, etc)
|
||||
(how useful would it really be, or is this just sorting legos?)
|
||||
o same for windowutils, fileutils, etc. (not useful)
|
||||
* StringBuffer/StringBuilder as mutable char*/wchar_t* argument
|
||||
NOTE: byte[]/char[] is probably better; it's trivial to convert to String
|
||||
and native code can't change the size anyway
|
||||
* provide library load/unload hooks (Runnables in options?). Examples:
|
||||
o GetLastError (no longer needed)
|
||||
o WSAInit?
|
||||
* determine X11 display name from current java program (if any); null is ok
|
||||
since it uses getenv(DISPLAY), which is what java would do
|
||||
note: DISPLAY may be available in GraphicsDevice->getIDstring
|
||||
|
||||
|
||||
|
||||
+29
-8
@@ -15,6 +15,7 @@
|
||||
<!-- (all build-related props should go in -dynamic-properties) -->
|
||||
<property name="name" value="jna"/>
|
||||
<property name="jar" value="${name}.jar"/>
|
||||
<property name="testjar" value="${name}-test.jar"/>
|
||||
<property name="debug" value="true"/>
|
||||
<property name="debug.native" value="false"/>
|
||||
<property name="cflags_extra.native" value=""/>
|
||||
@@ -28,21 +29,21 @@
|
||||
<property name="stylesheet" location="${javadoc}/doc/css/javadoc.css"/>
|
||||
<property name="vendor" value="JNA Development Team"/>
|
||||
<property name="copyright"
|
||||
value="Copyright &copy; 2007-2008 Timothy Wall. All Rights Reserved."/>
|
||||
value="Copyright &copy; 2007-2009 Timothy Wall. All Rights Reserved."/>
|
||||
<buildnumber/>
|
||||
<!-- JNA library release version -->
|
||||
<property name="jna.major" value="3"/>
|
||||
<property name="jna.minor" value="1"/>
|
||||
<property name="jna.revision" value="0"/>
|
||||
<property name="jna.minor" value="2"/>
|
||||
<property name="jna.revision" value="1"/>
|
||||
<property name="jna.build" value="${build.number}"/>
|
||||
<property name="jna.version" value="${jna.major}.${jna.minor}.${jna.revision}"/>
|
||||
<!-- jnidispatch library release version -->
|
||||
<property name="jni.major" value="3"/>
|
||||
<property name="jni.minor" value="1"/>
|
||||
<property name="jni.minor" value="2"/>
|
||||
<property name="jni.revision" value="0"/>
|
||||
<property name="jni.build" value="${build.number}"/>
|
||||
<property name="jni.version" value="${jni.major}.${jni.minor}.${jni.revision}"/>
|
||||
<property name="jni.md5" value="816e53324203bcffe46f43e482e5c286"/>
|
||||
<property name="jni.md5" value="c870290c36c8d3fdf85db7c782febc3f"/>
|
||||
<property name="spec.title" value="Java Native Access (JNA)"/>
|
||||
<property name="spec.vendor" value="${vendor}"/>
|
||||
<property name="spec.version" value="${jna.major}"/>
|
||||
@@ -64,8 +65,11 @@
|
||||
<target name="compile-single" depends="compile"/>
|
||||
|
||||
<target name="-dynamic-properties">
|
||||
<echo>Java version: ${java.version}, compatibility: ${compatibility}</echo>
|
||||
<echo>JNA version ${jna.version}, native API version ${jni.version}</echo>
|
||||
<echo>Java version ${java.version}, compatibility: ${compatibility}</echo>
|
||||
<echo>JNA version ${jna.version}, native ${jni.version}</echo>
|
||||
<echo>${java.vm.name} (${java.vm.vendor}, ${java.vm.version})</echo>
|
||||
<echo>java.home=${java.home}</echo>
|
||||
<echo>java.library.path=${java.library.path}</echo>
|
||||
|
||||
<replaceregexp match="(<version>).*(</version>)"
|
||||
replace="\1${jna.version}\2"
|
||||
@@ -77,6 +81,7 @@
|
||||
<condition property="vm.arch" value="-d64" else="">
|
||||
<or>
|
||||
<equals arg1="${sun.arch.data.model}" arg2="64" trim="true"/>
|
||||
<equals arg1="${com.ibm.vm.bitmode}" arg2="64" trim="true"/>
|
||||
<os arch="x86_64"/>
|
||||
<os arch="ppc64"/>
|
||||
<os arch="sparcv9"/>
|
||||
@@ -391,7 +396,7 @@
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
<target name="compile-tests" depends="compile,native"
|
||||
<target name="compile-tests" depends="compile,native,jar"
|
||||
description="Compile all test code">
|
||||
<javac classpathref="compile-test.path"
|
||||
source="${test.compatibility}"
|
||||
@@ -400,6 +405,22 @@
|
||||
deprecation="on" debug="${debug}">
|
||||
<src path="${test.src}"/>
|
||||
</javac>
|
||||
<jar jarfile="${build}/${testjar}">
|
||||
<fileset dir="${test.classes}">
|
||||
<patternset refid="jar-compiled"/>
|
||||
</fileset>
|
||||
</jar>
|
||||
<mkdir dir="${build}/jws"/>
|
||||
<copy todir="${build}/jws" file="${build}/${jar}"/>
|
||||
<copy todir="${build}/jws" file="${build}/${testjar}"/>
|
||||
<copy todir="${build}/jws" file="lib/junit.jar"/>
|
||||
<copy todir="${build}/jws" file="lib/clover.jar"/>
|
||||
<jar jarfile="${build}/jws/jnidispatch.jar">
|
||||
<fileset dir="${build.native}" includes="*jnidispatch.*"/>
|
||||
</jar>
|
||||
<signjar alias="jna" keystore="jna.keystore" storepass="jnadev" lazy="true">
|
||||
<fileset dir="${build}/jws" includes="jna.jar,jna-test.jar,junit.jar,jnidispatch.jar,clover.jar"/>
|
||||
</signjar>
|
||||
</target>
|
||||
|
||||
<!-- When running tests from an IDE, be sure to set jna.library.path -->
|
||||
|
||||
externo
BIN
Arquivo binário não exibido.
externo
BIN
Arquivo binário não exibido.
externo
BIN
Arquivo binário não exibido.
externo
BIN
Arquivo binário não exibido.
externo
BIN
Arquivo binário não exibido.
externo
BIN
Arquivo binário não exibido.
externo
BIN
Arquivo binário não exibido.
externo
BIN
Arquivo binário não exibido.
externo
BIN
Arquivo binário não exibido.
externo
BIN
Arquivo binário não exibido.
externo
BIN
Arquivo binário não exibido.
externo
BIN
Arquivo binário não exibido.
externo
BIN
Arquivo binário não exibido.
externo
BIN
Arquivo binário não exibido.
externo
BIN
Arquivo binário não exibido.
Arquivo binário não exibido.
Arquivo binário não exibido.
@@ -1,5 +1,5 @@
|
||||
nQMpVtdkeiLDhkfVhlebsGWVMnsDeqDAmHuaUJSRUxwraf
|
||||
mi2K4SaejnjOrPDIm3nJq8<b2Ke>wQwCu3>RYeCLGxFda>
|
||||
PRoQxwONRmmnMpmQRPQvuNmQoQpMQRMpOnSSTxXMvwWmvu
|
||||
VtqwVvXwqqRnmqmUUnnvuvvqqmmmmmUUnnvuvvqqmmmmmU
|
||||
UgkXkabskgXsXkkbqUUnmm
|
||||
qRNQnmsMoNMDGXUenVfHVPuFPrNBGUUdBvfgtIdgVQWSbAa
|
||||
mj2KW7Oo9ud83ZbEKfK2xx922L04T>gYjDdLjGld4Wa6MPW
|
||||
NrqPtxROppqOmmqROMPSTnMmRqNOMnMnoPVSXswPsVXQwXV
|
||||
SPVVUtUNQmnmqmUUnopmqsvommmmmUUnopmqsvommmmmUUg
|
||||
kXkabskgXsXkkbqUUnmm
|
||||
|
||||
@@ -27,8 +27,8 @@ OS=$(shell uname | sed -e 's/\(CYGWIN\|MINGW32\).*/win32/g' \
|
||||
-e 's/Darwin.*/darwin/g' \
|
||||
-e 's/Linux.*/linux/g')
|
||||
|
||||
VERSION=3.1.0 # auto-generated by ant
|
||||
CHECKSUM=816e53324203bcffe46f43e482e5c286 # auto-generated by ant
|
||||
VERSION=3.2.0 # auto-generated by ant
|
||||
CHECKSUM=c870290c36c8d3fdf85db7c782febc3f # auto-generated by ant
|
||||
|
||||
JAVA_INCLUDES=-I"$(JAVA_HOME)/include" \
|
||||
-I"$(JAVA_HOME)/include/$(OS)"
|
||||
@@ -42,7 +42,7 @@ ifneq ($(DYNAMIC_LIBFFI),true)
|
||||
FFI_SRC=$(shell pwd)/libffi
|
||||
FFI_BUILD=$(BUILD)/libffi
|
||||
FFI_LIB=$(FFI_BUILD)/.libs/libffi$(ARSFX)
|
||||
FFI_ENV=CC="$(CC)" CFLAGS="$(CDEBUG)" CPPFLAGS="$(CDEFINES)"
|
||||
FFI_ENV=CC="$(CC)" CFLAGS="$(COPT) $(CDEBUG)" CPPFLAGS="$(CDEFINES)"
|
||||
FFI_CONFIG=--enable-static --disable-shared --with-pic=yes
|
||||
endif
|
||||
LIBRARY=$(BUILD)/$(LIBPFX)jnidispatch$(JNISFX)
|
||||
@@ -58,8 +58,7 @@ CC=gcc
|
||||
LD=gcc
|
||||
LIBS=
|
||||
# Default to Sun recommendations for JNI compilation
|
||||
#COPT=-O2 -fomit-frame-pointer
|
||||
COPT=-fno-omit-frame-pointer -fno-strict-aliasing
|
||||
COPT=-O2 -fno-omit-frame-pointer -fno-strict-aliasing
|
||||
CASM=-S
|
||||
ifeq ($(DEBUG),true)
|
||||
CDEBUG=-g
|
||||
@@ -87,7 +86,8 @@ STRIP=strip -x
|
||||
|
||||
ifeq ($(OS),win32)
|
||||
ARCH=$(shell uname -m | sed 's/i.86/i386/g')
|
||||
CDEFINES=-DHAVE_PROTECTION
|
||||
CDEFINES=-DHAVE_PROTECTION -DPSAPI_VERSION=1
|
||||
LIBS=-lpsapi
|
||||
WINDRES=windres
|
||||
EXTRAOBJS=$(RSRC)
|
||||
STRIP=@echo
|
||||
@@ -104,18 +104,20 @@ ifeq ($(ARCH),amd64)
|
||||
WINDRES=/usr/local/mingw64-cross/bin/x86_64-pc-mingw32-windres
|
||||
|
||||
# Uncomment to enable MINGW64 cross compiler
|
||||
# Last build attempt has too many runtime problems (alloca broken) (080831)
|
||||
# Should build properly as of 090601, but lacks SEH, so MSVC build is preferred
|
||||
#MINGW = x86_64-pc-mingw32-gcc
|
||||
ifneq ($(MINGW),)
|
||||
CC = $(MINGW) -m64 -mno-cygwin
|
||||
LD = $(CC)
|
||||
LDFLAGS=-o $@ -shared
|
||||
LIBS= -lmingwex -lkernel32 -lmsvcrt
|
||||
LIBS= -lmingwex -lpsapi -lkernel32 -lmsvcrt
|
||||
FFI_CONFIG += --host=x86_64-pc-mingw32
|
||||
else
|
||||
# MSVC (wrapper scripts)
|
||||
CC=$(FFI_SRC)/../cc.sh -m64
|
||||
LD=$(FFI_SRC)/../ld.sh -m64
|
||||
COPT=
|
||||
LIBS=psapi.lib
|
||||
ARSFX=.lib
|
||||
FFI_CONFIG += --host=x86_64-pc-mingw32 && rm -f include/ffitarget.h && cp $(FFI_SRC)/include/*.h $(FFI_SRC)/src/x86/ffitarget.h include
|
||||
FFI_ENV += LD="$(LD)" CPP=cpp
|
||||
|
||||
+248
-44
@@ -37,89 +37,177 @@ static jclass classObject;
|
||||
callback*
|
||||
create_callback(JNIEnv* env, jobject obj, jobject method,
|
||||
jobjectArray param_types, jclass return_type,
|
||||
callconv_t calling_convention) {
|
||||
callconv_t calling_convention, jboolean direct) {
|
||||
callback* cb;
|
||||
ffi_abi abi = FFI_DEFAULT_ABI;
|
||||
ffi_abi java_abi = FFI_DEFAULT_ABI;
|
||||
ffi_type* ffi_rtype;
|
||||
ffi_status status;
|
||||
jsize argc;
|
||||
JavaVM* vm;
|
||||
char rtype;
|
||||
int rtype;
|
||||
char msg[64];
|
||||
int i;
|
||||
int cvt = 0;
|
||||
const char* throw_type = NULL;
|
||||
const char* throw_msg = NULL;
|
||||
|
||||
if ((*env)->GetJavaVM(env, &vm) != JNI_OK) {
|
||||
throwByName(env, EUnsatisfiedLink, "Can't get Java VM");
|
||||
return NULL;
|
||||
}
|
||||
argc = (*env)->GetArrayLength(env, param_types);
|
||||
|
||||
cb = (callback *)malloc(sizeof(callback));
|
||||
cb->ffi_closure = ffi_closure_alloc(sizeof(ffi_closure), &cb->x_closure);
|
||||
cb->closure = ffi_closure_alloc(sizeof(ffi_closure), &cb->x_closure);
|
||||
cb->object = (*env)->NewWeakGlobalRef(env, obj);
|
||||
cb->methodID = (*env)->FromReflectedMethod(env, method);
|
||||
cb->vm = vm;
|
||||
cb->arg_types = (ffi_type**)malloc(sizeof(ffi_type*) * argc);
|
||||
cb->java_arg_types = (ffi_type**)malloc(sizeof(ffi_type*) * (argc + 3));
|
||||
cb->arg_jtypes = (char*)malloc(sizeof(char) * argc);
|
||||
cb->flags = (int *)malloc(sizeof(int) * argc);
|
||||
cb->rflag = CVT_DEFAULT;
|
||||
cb->arg_classes = (jobject*)malloc(sizeof(jobject) * argc);
|
||||
|
||||
cb->direct = direct;
|
||||
cb->java_arg_types[0] = cb->java_arg_types[1] = cb->java_arg_types[2] = &ffi_type_pointer;
|
||||
|
||||
for (i=0;i < argc;i++) {
|
||||
int jtype;
|
||||
jclass cls = (*env)->GetObjectArrayElement(env, param_types, i);
|
||||
cb->param_jtypes[i] = get_jtype(env, cls);
|
||||
cb->ffi_args[i] = get_ffi_type(env, cls, cb->param_jtypes[i]);
|
||||
if (!cb->param_jtypes[i]) {
|
||||
snprintf(msg, sizeof(msg), "Unsupported type at parameter %d", i);
|
||||
throwByName(env, EIllegalArgument, msg);
|
||||
if ((cb->flags[i] = get_conversion_flag(env, cls)) != CVT_DEFAULT) {
|
||||
cb->arg_classes[i] = (*env)->NewWeakGlobalRef(env, cls);
|
||||
cvt = 1;
|
||||
}
|
||||
|
||||
jtype = get_jtype(env, cls);
|
||||
if (jtype == -1) {
|
||||
snprintf(msg, sizeof(msg), "Unsupported argument at index %d", i);
|
||||
throw_type = EIllegalArgument;
|
||||
throw_msg = msg;
|
||||
goto failure_cleanup;
|
||||
}
|
||||
cb->arg_jtypes[i] = (char)jtype;
|
||||
cb->java_arg_types[i+3] = cb->arg_types[i] = get_ffi_type(env, cls, cb->arg_jtypes[i]);
|
||||
if (cb->flags[i] == CVT_NATIVE_MAPPED
|
||||
|| cb->flags[i] == CVT_POINTER_TYPE
|
||||
|| cb->flags[i] == CVT_INTEGER_TYPE) {
|
||||
jclass ncls;
|
||||
ncls = getNativeType(env, cls);
|
||||
jtype = get_jtype(env, ncls);
|
||||
if (jtype == -1) {
|
||||
snprintf(msg, sizeof(msg), "Unsupported NativeMapped argument native type at argument %d", i);
|
||||
throw_type = EIllegalArgument;
|
||||
throw_msg = msg;
|
||||
goto failure_cleanup;
|
||||
}
|
||||
cb->arg_jtypes[i] = (char)jtype;
|
||||
cb->java_arg_types[i+3] = &ffi_type_pointer;
|
||||
cb->arg_types[i] = get_ffi_type(env, ncls, cb->arg_jtypes[i]);
|
||||
}
|
||||
|
||||
if (cb->arg_types[i]->type == FFI_TYPE_FLOAT) {
|
||||
// Java method is varargs, so promote floats to double
|
||||
cb->java_arg_types[i+3] = &ffi_type_double;
|
||||
cb->flags[i] = CVT_FLOAT;
|
||||
cvt = 1;
|
||||
}
|
||||
else if (cb->java_arg_types[i+3]->type == FFI_TYPE_STRUCT) {
|
||||
// All callback structure arguments are passed as a jobject
|
||||
cb->java_arg_types[i+3] = &ffi_type_pointer;
|
||||
}
|
||||
}
|
||||
if (!direct || !cvt) {
|
||||
free(cb->flags);
|
||||
cb->flags = NULL;
|
||||
free(cb->arg_classes);
|
||||
cb->arg_classes = NULL;
|
||||
}
|
||||
if (direct) {
|
||||
cb->rflag = get_conversion_flag(env, return_type);
|
||||
if (cb->rflag == CVT_NATIVE_MAPPED
|
||||
|| cb->rflag == CVT_INTEGER_TYPE
|
||||
|| cb->rflag == CVT_POINTER_TYPE) {
|
||||
return_type = getNativeType(env, return_type);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(_WIN32) && !defined(_WIN64)
|
||||
if (calling_convention == CALLCONV_STDCALL) {
|
||||
abi = FFI_STDCALL;
|
||||
}
|
||||
java_abi = FFI_STDCALL;
|
||||
#endif // _WIN32
|
||||
|
||||
rtype = get_jtype(env, return_type);
|
||||
if (!rtype) {
|
||||
throwByName(env, EIllegalArgument, "Unsupported return type");
|
||||
if (rtype == -1) {
|
||||
throw_type = EIllegalArgument;
|
||||
throw_msg = "Unsupported return type";
|
||||
goto failure_cleanup;
|
||||
}
|
||||
ffi_rtype = get_ffi_rtype(env, return_type, rtype);
|
||||
ffi_rtype = get_ffi_rtype(env, return_type, (char)rtype);
|
||||
if (!ffi_rtype) {
|
||||
throwByName(env, EIllegalArgument, "Error in return type");
|
||||
throw_type = EIllegalArgument;
|
||||
throw_msg = "Error in return type";
|
||||
goto failure_cleanup;
|
||||
}
|
||||
status = ffi_prep_cif(&cb->ffi_cif, abi, argc, ffi_rtype, &cb->ffi_args[0]);
|
||||
status = ffi_prep_cif(&cb->cif, abi, argc, ffi_rtype, cb->arg_types);
|
||||
if (!ffi_error(env, "callback setup", status)) {
|
||||
ffi_type* java_ffi_rtype = ffi_rtype;
|
||||
|
||||
switch(status) {
|
||||
case FFI_BAD_ABI:
|
||||
snprintf(msg, sizeof(msg),
|
||||
"Invalid calling convention: %d", (int)calling_convention);
|
||||
throwByName(env, EIllegalArgument, msg);
|
||||
break;
|
||||
case FFI_BAD_TYPEDEF:
|
||||
snprintf(msg, sizeof(msg),
|
||||
"Invalid structure definition (native typedef error)");
|
||||
throwByName(env, EIllegalArgument, msg);
|
||||
break;
|
||||
case FFI_OK:
|
||||
ffi_prep_closure_loc(cb->ffi_closure, &cb->ffi_cif, callback_dispatch, cb,
|
||||
cb->x_closure);
|
||||
|
||||
return cb;
|
||||
default:
|
||||
snprintf(msg, sizeof(msg),
|
||||
"Native callback setup failure: error code %d", status);
|
||||
throwByName(env, EIllegalArgument, msg);
|
||||
break;
|
||||
if (cb->rflag == CVT_STRUCTURE_BYVAL
|
||||
|| cb->rflag == CVT_NATIVE_MAPPED
|
||||
|| cb->rflag == CVT_POINTER_TYPE
|
||||
|| cb->rflag == CVT_INTEGER_TYPE) {
|
||||
// Java method returns a jobject, not a struct
|
||||
java_ffi_rtype = &ffi_type_pointer;
|
||||
rtype = '*';
|
||||
}
|
||||
switch(rtype) {
|
||||
case 'V': cb->fptr = (*env)->CallVoidMethod; break;
|
||||
case 'Z': cb->fptr = (*env)->CallBooleanMethod; break;
|
||||
case 'B': cb->fptr = (*env)->CallByteMethod; break;
|
||||
case 'S': cb->fptr = (*env)->CallShortMethod; break;
|
||||
case 'C': cb->fptr = (*env)->CallCharMethod; break;
|
||||
case 'I': cb->fptr = (*env)->CallIntMethod; break;
|
||||
case 'J': cb->fptr = (*env)->CallLongMethod; break;
|
||||
case 'F': cb->fptr = (*env)->CallFloatMethod; break;
|
||||
case 'D': cb->fptr = (*env)->CallDoubleMethod; break;
|
||||
default: cb->fptr = (*env)->CallObjectMethod; break;
|
||||
}
|
||||
status = ffi_prep_cif(&cb->java_cif, java_abi, argc+3, java_ffi_rtype, cb->java_arg_types);
|
||||
if (!ffi_error(env, "callback setup (2)", status)) {
|
||||
ffi_prep_closure_loc(cb->closure, &cb->cif, callback_dispatch, cb,
|
||||
cb->x_closure);
|
||||
return cb;
|
||||
}
|
||||
}
|
||||
|
||||
failure_cleanup:
|
||||
free_callback(env, cb);
|
||||
if (throw_type) {
|
||||
throwByName(env, throw_type, msg);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
void
|
||||
free_callback(JNIEnv* env, callback *cb) {
|
||||
(*env)->DeleteWeakGlobalRef(env, cb->object);
|
||||
ffi_closure_free(cb->ffi_closure);
|
||||
ffi_closure_free(cb->closure);
|
||||
free(cb->arg_types);
|
||||
if (cb->arg_classes) {
|
||||
unsigned i;
|
||||
for (i=0;i < cb->cif.nargs;i++) {
|
||||
(*env)->DeleteWeakGlobalRef(env, cb->arg_classes[i]);
|
||||
}
|
||||
free(cb->arg_classes);
|
||||
}
|
||||
free(cb->java_arg_types);
|
||||
if (cb->flags)
|
||||
free(cb->flags);
|
||||
free(cb->arg_jtypes);
|
||||
free(cb);
|
||||
}
|
||||
|
||||
@@ -140,7 +228,9 @@ handle_exception(JNIEnv* env, jobject cb, jthrowable throwable) {
|
||||
if (!(*env)->IsSameObject(env, handler, NULL)) {
|
||||
(*env)->CallVoidMethod(env, handler, mid, cb, throwable);
|
||||
}
|
||||
return (*env)->ExceptionCheck(env) == 0;
|
||||
if ((*env)->ExceptionCheck(env) == 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -154,12 +244,124 @@ handle_exception(JNIEnv* env, jobject cb, jthrowable throwable) {
|
||||
static void
|
||||
callback_invoke(JNIEnv* env, callback *cb, ffi_cif* cif, void *resp, void **cbargs) {
|
||||
jobject self;
|
||||
void *oldresp = resp;
|
||||
|
||||
self = (*env)->NewLocalRef(env, cb->object);
|
||||
// Avoid calling back to a GC'd object
|
||||
if ((*env)->IsSameObject(env, self, NULL)) {
|
||||
fprintf(stderr, "JNA: callback object has been garbage collected\n");
|
||||
memset(resp, 0, cif->rtype->size);
|
||||
if (cif->rtype->type != FFI_TYPE_VOID)
|
||||
memset(resp, 0, cif->rtype->size);
|
||||
}
|
||||
else if (cb->direct) {
|
||||
unsigned int i;
|
||||
void **args = alloca((cif->nargs + 3) * sizeof(void *));
|
||||
args[0] = (void *)&env;
|
||||
args[1] = &self;
|
||||
args[2] = &cb->methodID;
|
||||
memcpy(&args[3], cbargs, cif->nargs * sizeof(void *));
|
||||
|
||||
if (cb->flags) {
|
||||
for (i=0;i < cif->nargs;i++) {
|
||||
switch(cb->flags[i]) {
|
||||
case CVT_INTEGER_TYPE:
|
||||
case CVT_POINTER_TYPE:
|
||||
case CVT_NATIVE_MAPPED:
|
||||
*((void **)args[i+3]) = fromNative(env, cb->arg_classes[i], cif->arg_types[i], args[i+3], JNI_FALSE);
|
||||
break;
|
||||
case CVT_POINTER:
|
||||
*((void **)args[i+3]) = newJavaPointer(env, *(void **)args[i+3]);
|
||||
break;
|
||||
case CVT_STRING:
|
||||
*((void **)args[i+3]) = newJavaString(env, *(void **)args[i+3], JNI_FALSE);
|
||||
break;
|
||||
case CVT_WSTRING:
|
||||
*((void **)args[i+3]) = newJavaWString(env, *(void **)args[i+3]);
|
||||
break;
|
||||
case CVT_STRUCTURE:
|
||||
*((void **)args[i+3]) = newJavaStructure(env, *(void **)args[i+3], cb->arg_classes[i], JNI_FALSE);
|
||||
break;
|
||||
case CVT_STRUCTURE_BYVAL:
|
||||
{
|
||||
void *ptr = args[i+3];
|
||||
args[i+3] = alloca(sizeof(void *));
|
||||
*((void **)args[i+3]) = newJavaStructure(env, ptr, cb->arg_classes[i], JNI_TRUE);
|
||||
}
|
||||
break;
|
||||
case CVT_CALLBACK:
|
||||
*((void **)args[i+3]) = newJavaCallback(env, *(void **)args[i+3], cb->arg_classes[i]);
|
||||
break;
|
||||
case CVT_FLOAT:
|
||||
{
|
||||
void *ptr = alloca(sizeof(double));
|
||||
*(double *)ptr = *(float*)args[i+3];
|
||||
args[i+3] = ptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cb->rflag == CVT_STRUCTURE_BYVAL) {
|
||||
resp = alloca(sizeof(jobject));
|
||||
}
|
||||
else if (cb->cif.rtype->size > cif->rtype->size) {
|
||||
resp = alloca(cb->cif.rtype->size);
|
||||
}
|
||||
ffi_call(&cb->java_cif, FFI_FN(cb->fptr), resp, args);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
jthrowable throwable = (*env)->ExceptionOccurred(env);
|
||||
(*env)->ExceptionClear(env);
|
||||
if (!handle_exception(env, self, throwable)) {
|
||||
fprintf(stderr, "JNA: error handling callback exception, continuing\n");
|
||||
}
|
||||
if (cif->rtype->type != FFI_TYPE_VOID)
|
||||
memset(oldresp, 0, cif->rtype->size);
|
||||
}
|
||||
else switch(cb->rflag) {
|
||||
case CVT_INTEGER_TYPE:
|
||||
if (cb->cif.rtype->size > sizeof(ffi_arg)) {
|
||||
*(jlong *)oldresp = getIntegerTypeValue(env, *(void **)resp);
|
||||
}
|
||||
else {
|
||||
*(ffi_arg *)oldresp = (ffi_arg)getIntegerTypeValue(env, *(void **)resp);
|
||||
}
|
||||
break;
|
||||
case CVT_POINTER_TYPE:
|
||||
*(void **)resp = getPointerTypeAddress(env, *(void **)resp);
|
||||
break;
|
||||
case CVT_NATIVE_MAPPED:
|
||||
toNative(env, *(void **)resp, oldresp, cb->cif.rtype->size, JNI_TRUE);
|
||||
break;
|
||||
case CVT_POINTER:
|
||||
*(void **)resp = getNativeAddress(env, *(void **)resp);
|
||||
break;
|
||||
case CVT_STRING:
|
||||
*(void **)resp = getNativeString(env, *(void **)resp, JNI_FALSE);
|
||||
break;
|
||||
case CVT_WSTRING:
|
||||
*(void **)resp = getNativeString(env, *(void **)resp, JNI_TRUE);
|
||||
break;
|
||||
case CVT_STRUCTURE:
|
||||
writeStructure(env, *(void **)resp);
|
||||
*(void **)resp = getStructureAddress(env, *(void **)resp);
|
||||
break;
|
||||
case CVT_STRUCTURE_BYVAL:
|
||||
writeStructure(env, *(void **)resp);
|
||||
memcpy(oldresp, getStructureAddress(env, *(void **)resp), cb->cif.rtype->size);
|
||||
break;
|
||||
case CVT_CALLBACK:
|
||||
*(void **)resp = getCallbackAddress(env, *(void **)resp);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
if (cb->flags) {
|
||||
for (i=0;i < cif->nargs;i++) {
|
||||
if (cb->flags[i] == CVT_STRUCTURE) {
|
||||
writeStructure(env, *(void **)args[i+3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
jobject result;
|
||||
@@ -168,7 +370,7 @@ callback_invoke(JNIEnv* env, callback *cb, ffi_cif* cif, void *resp, void **cbar
|
||||
unsigned int i;
|
||||
|
||||
for (i=0;i < cif->nargs;i++) {
|
||||
jobject arg = new_object(env, cb->param_jtypes[i], cbargs[i]);
|
||||
jobject arg = new_object(env, cb->arg_jtypes[i], cbargs[i], JNI_FALSE);
|
||||
(*env)->SetObjectArrayElement(env, array, i, arg);
|
||||
}
|
||||
result = (*env)->CallObjectMethod(env, self, cb->methodID, array);
|
||||
@@ -178,10 +380,11 @@ callback_invoke(JNIEnv* env, callback *cb, ffi_cif* cif, void *resp, void **cbar
|
||||
if (!handle_exception(env, self, throwable)) {
|
||||
fprintf(stderr, "JNA: error handling callback exception, continuing\n");
|
||||
}
|
||||
memset(resp, 0, cif->rtype->size);
|
||||
if (cif->rtype->type != FFI_TYPE_VOID)
|
||||
memset(resp, 0, cif->rtype->size);
|
||||
}
|
||||
else {
|
||||
extract_value(env, result, resp, cif->rtype->size);
|
||||
extract_value(env, result, resp, cif->rtype->size, JNI_TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -204,11 +407,12 @@ callback_dispatch(ffi_cif* cif, void* resp, void** cbargs, void* user_data) {
|
||||
// are properly disposed
|
||||
if ((*env)->PushLocalFrame(env, 16) < 0) {
|
||||
fprintf(stderr, "JNA: Out of memory: Can't allocate local frame");
|
||||
return;
|
||||
}
|
||||
callback_invoke(env, (callback *)user_data, cif, resp, cbargs);
|
||||
(*env)->PopLocalFrame(env, NULL);
|
||||
|
||||
else {
|
||||
callback_invoke(env, (callback *)user_data, cif, resp, cbargs);
|
||||
(*env)->PopLocalFrame(env, NULL);
|
||||
}
|
||||
|
||||
if (!attached) {
|
||||
(*jvm)->DetachCurrentThread(jvm);
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ do
|
||||
shift 1
|
||||
;;
|
||||
-O*)
|
||||
args="$args /O1"
|
||||
args="$args $i"
|
||||
shift 1
|
||||
;;
|
||||
-g)
|
||||
|
||||
+1018
-265
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+76
-12
@@ -15,6 +15,22 @@
|
||||
|
||||
#include "ffi.h"
|
||||
#include "com_sun_jna_Function.h"
|
||||
#include "com_sun_jna_Native.h"
|
||||
#ifdef sun
|
||||
# include <alloca.h>
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#ifdef _MSC_VER
|
||||
#define alloca _alloca
|
||||
#pragma warning( disable : 4152 ) /* function/data conversion */
|
||||
#pragma warning( disable : 4054 ) /* cast function pointer to data pointer */
|
||||
#pragma warning( disable : 4055 ) /* cast data pointer to function pointer */
|
||||
#pragma warning( disable : 4204 ) /* structure initializer */
|
||||
#pragma warning( disable : 4710 ) /* swprintf not inlined */
|
||||
#else
|
||||
#include <malloc.h>
|
||||
#endif /* _MSC_VER */
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -31,21 +47,50 @@ typedef enum _callconv {
|
||||
/* Maximum number of allowed arguments in libffi. */
|
||||
#define MAX_NARGS com_sun_jna_Function_MAX_NARGS
|
||||
|
||||
enum {
|
||||
CVT_DEFAULT = com_sun_jna_Native_CVT_DEFAULT,
|
||||
CVT_POINTER = com_sun_jna_Native_CVT_POINTER,
|
||||
CVT_STRING = com_sun_jna_Native_CVT_STRING,
|
||||
CVT_STRUCTURE = com_sun_jna_Native_CVT_STRUCTURE,
|
||||
CVT_STRUCTURE_BYVAL = com_sun_jna_Native_CVT_STRUCTURE_BYVAL,
|
||||
CVT_BUFFER = com_sun_jna_Native_CVT_BUFFER,
|
||||
CVT_ARRAY_BYTE = com_sun_jna_Native_CVT_ARRAY_BYTE,
|
||||
CVT_ARRAY_SHORT = com_sun_jna_Native_CVT_ARRAY_SHORT,
|
||||
CVT_ARRAY_CHAR = com_sun_jna_Native_CVT_ARRAY_CHAR,
|
||||
CVT_ARRAY_INT = com_sun_jna_Native_CVT_ARRAY_INT,
|
||||
CVT_ARRAY_LONG = com_sun_jna_Native_CVT_ARRAY_LONG,
|
||||
CVT_ARRAY_FLOAT = com_sun_jna_Native_CVT_ARRAY_FLOAT,
|
||||
CVT_ARRAY_DOUBLE = com_sun_jna_Native_CVT_ARRAY_DOUBLE,
|
||||
CVT_ARRAY_BOOLEAN = com_sun_jna_Native_CVT_ARRAY_BOOLEAN,
|
||||
CVT_BOOLEAN = com_sun_jna_Native_CVT_BOOLEAN,
|
||||
CVT_CALLBACK = com_sun_jna_Native_CVT_CALLBACK,
|
||||
CVT_FLOAT = com_sun_jna_Native_CVT_FLOAT,
|
||||
CVT_NATIVE_MAPPED = com_sun_jna_Native_CVT_NATIVE_MAPPED,
|
||||
CVT_WSTRING = com_sun_jna_Native_CVT_WSTRING,
|
||||
CVT_INTEGER_TYPE = com_sun_jna_Native_CVT_INTEGER_TYPE,
|
||||
CVT_POINTER_TYPE = com_sun_jna_Native_CVT_POINTER_TYPE,
|
||||
CVT_TYPE_MAPPER = com_sun_jna_Native_CVT_TYPE_MAPPER,
|
||||
};
|
||||
|
||||
typedef struct _callback {
|
||||
// Location of this field must agree with CallbackReference.getTrampoline()
|
||||
void* x_closure;
|
||||
ffi_closure* ffi_closure;
|
||||
ffi_cif ffi_cif;
|
||||
ffi_type* ffi_args[MAX_NARGS];
|
||||
ffi_closure* closure;
|
||||
ffi_cif cif;
|
||||
ffi_cif java_cif;
|
||||
ffi_type** arg_types;
|
||||
ffi_type** java_arg_types;
|
||||
jobject* arg_classes;
|
||||
int* flags;
|
||||
int rflag;
|
||||
JavaVM* vm;
|
||||
jobject object;
|
||||
jmethodID methodID;
|
||||
char param_jtypes[MAX_NARGS];
|
||||
char* arg_jtypes;
|
||||
jboolean direct;
|
||||
void* fptr;
|
||||
} callback;
|
||||
|
||||
// Size of a register
|
||||
typedef long word_t;
|
||||
|
||||
#if defined(SOLARIS2) || defined(__GNUC__)
|
||||
#if defined(_WIN64)
|
||||
#define L2A(X) ((void *)(long long)(X))
|
||||
@@ -87,22 +132,41 @@ typedef long word_t;
|
||||
#define EUnsatisfiedLink "java/lang/UnsatisfiedLinkError"
|
||||
#define EIllegalState "java/lang/IllegalStateException"
|
||||
#define EUnsupportedOperation "java/lang/UnsupportedOperationException"
|
||||
#define ERuntime "java/lang/RuntimeException"
|
||||
#define EError "java/lang/Error"
|
||||
#define ELastError "com/sun/jna/LastErrorException"
|
||||
|
||||
extern void throwByName(JNIEnv *env, const char *name, const char *msg);
|
||||
extern jobject newJavaPointer(JNIEnv *, void *);
|
||||
extern char get_jtype(JNIEnv*, jclass);
|
||||
extern int get_jtype(JNIEnv*, jclass);
|
||||
extern ffi_type* get_ffi_type(JNIEnv*, jclass, char);
|
||||
extern ffi_type* get_ffi_rtype(JNIEnv*, jclass, char);
|
||||
extern const char* jnidispatch_callback_init(JNIEnv*);
|
||||
extern void jnidispatch_callback_dispose(JNIEnv*);
|
||||
extern callback* create_callback(JNIEnv*, jobject, jobject,
|
||||
jobjectArray, jclass,
|
||||
callconv_t);
|
||||
callconv_t, jboolean);
|
||||
extern void free_callback(JNIEnv*, callback*);
|
||||
extern void extract_value(JNIEnv*, jobject, void*, size_t size);
|
||||
extern jobject new_object(JNIEnv*, char, void*);
|
||||
extern void extract_value(JNIEnv*, jobject, void*, size_t, jboolean);
|
||||
extern jobject new_object(JNIEnv*, char, void*, jboolean);
|
||||
extern jboolean is_protected();
|
||||
extern int get_conversion_flag(JNIEnv*, jclass);
|
||||
extern jboolean ffi_error(JNIEnv*,const char*,ffi_status);
|
||||
|
||||
extern jobject newJavaPointer(JNIEnv*, void*);
|
||||
extern jstring newJavaString(JNIEnv*, const char*, jboolean);
|
||||
extern jobject newJavaWString(JNIEnv*, const wchar_t*);
|
||||
extern jobject newJavaStructure(JNIEnv*, void*, jclass, jboolean);
|
||||
extern jobject newJavaCallback(JNIEnv*, void*, jclass);
|
||||
extern void* getNativeString(JNIEnv*, jstring, jboolean);
|
||||
extern void* getNativeAddress(JNIEnv*, jobject);
|
||||
extern void* getStructureAddress(JNIEnv*, jobject);
|
||||
extern void* getCallbackAddress(JNIEnv*, jobject);
|
||||
extern jlong getIntegerTypeValue(JNIEnv*, jobject);
|
||||
extern void* getPointerTypeAddress(JNIEnv*, jobject);
|
||||
extern void writeStructure(JNIEnv*, jobject);
|
||||
extern jclass getNativeType(JNIEnv*, jclass);
|
||||
extern void toNative(JNIEnv*, jobject, void*, size_t, jboolean);
|
||||
extern jclass fromNative(JNIEnv*, jclass, ffi_type*, void*, jboolean);
|
||||
|
||||
/* Native memory fault protection */
|
||||
#ifdef HAVE_PROTECTION
|
||||
|
||||
@@ -1,3 +1,66 @@
|
||||
2009-06-16 Wim Lewis <wiml@hhhh.org>
|
||||
|
||||
* src/powerpc/ffi.c: Avoid clobbering cr3 and cr4, which are
|
||||
supposed to be callee-saved.
|
||||
* src/powerpc/sysv.S (small_struct_return_value): Fix overrun of
|
||||
return buffer for odd-size structs.
|
||||
|
||||
2009-06-16 Andreas Tobler <a.tobler@schweiz.org>
|
||||
|
||||
PR libffi/40444
|
||||
* testsuite/lib/libffi-dg.exp (libffi_target_compile): Add
|
||||
allow_stack_execute for Darwin.
|
||||
|
||||
2009-06-16 Andrew Haley <aph@redhat.com>
|
||||
|
||||
* configure.ac (TARGETDIR): Add missing blank lines.
|
||||
* configure: Regenerate.
|
||||
|
||||
2009-06-16 Andrew Haley <aph@redhat.com>
|
||||
|
||||
* testsuite/libffi.call/err_bad_typedef.c: xfail everywhere.
|
||||
* testsuite/libffi.call/err_bad_abi.c: Likewise.
|
||||
|
||||
2009-06-11 Kaz Kojima <kkojima@gcc.gnu.org>
|
||||
|
||||
* testsuite/libffi.call/cls_longdouble_va.c: Add xfail sh*-*-linux-*.
|
||||
* testsuite/libffi.call/err_bad_abi.c: Add xfail sh*-*-*.
|
||||
* testsuite/libffi.call/err_bad_typedef.c: Likewise.
|
||||
|
||||
2009-06-08 Andrew Haley <aph@redhat.com>
|
||||
|
||||
* testsuite/libffi.call/err_bad_abi.c: Add xfails.
|
||||
* testsuite/libffi.call/cls_longdouble_va.c: Add xfails.
|
||||
* testsuite/libffi.call/cls_dbls_struct.c: Add xfail x86_64-*-linux-*.
|
||||
* testsuite/libffi.call/err_bad_typedef.c: Add xfails.
|
||||
|
||||
* testsuite/libffi.call/stret_medium2.c: Add __UNUSED__ to args.
|
||||
* testsuite/libffi.call/stret_medium.c: Likewise.
|
||||
* testsuite/libffi.call/stret_large2.c: Likewise.
|
||||
* testsuite/libffi.call/stret_large.c: Likewise.
|
||||
|
||||
2009-06-05 Andrew Haley <aph@redhat.com>
|
||||
|
||||
* src/x86/win32.S (_ffi_closure_STDCALL): Import from gcc.
|
||||
|
||||
2009-05-22 Dave Korn <dave.korn.cygwin@gmail.com>
|
||||
|
||||
* src/x86/win32.S (_ffi_closure_STDCALL): New function.
|
||||
(.eh_frame): Add FDE for it.
|
||||
|
||||
2009-05-22 Dave Korn <dave.korn.cygwin@gmail.com>
|
||||
|
||||
* configure.ac: Also check if assembler supports pc-relative
|
||||
relocs on X86_WIN32 targets.
|
||||
* configure: Regenerate.
|
||||
* src/x86/win32.S (ffi_prep_args): Declare extern, not global.
|
||||
(_ffi_call_SYSV): Add missing function type symbol .def and
|
||||
add EH markup labels.
|
||||
(_ffi_call_STDCALL): Likewise.
|
||||
(_ffi_closure_SYSV): Likewise.
|
||||
(_ffi_closure_raw_SYSV): Likewise.
|
||||
(.eh_frame): Add hand-crafted EH data.
|
||||
|
||||
2008-12-18 Rainer Orth <ro@TechFak.Uni-Bielefeld.DE>
|
||||
|
||||
PR libffi/26048
|
||||
@@ -12,6 +75,68 @@
|
||||
(.Lload_table): Likewise.
|
||||
(.eh_frame): Only use SYMBOL-. iff HAVE_AS_X86_PCREL.
|
||||
|
||||
2008-11-21 Eric Botcazou <ebotcazou@adacore.com>
|
||||
|
||||
* src/sparc/ffi.c (ffi_prep_cif_machdep): Add support for
|
||||
signed/unsigned int8/16 return values.
|
||||
* src/sparc/v8.S (ffi_call_v8): Likewise.
|
||||
(ffi_closure_v8): Likewise.
|
||||
|
||||
2008-08-25 Andreas Tobler <a.tobler@schweiz.org>
|
||||
|
||||
* src/powerpc/ffitarget.h (ffi_abi): Add FFI_LINUX and
|
||||
FFI_LINUX_SOFT_FLOAT to the POWERPC_FREEBSD enum.
|
||||
Add note about flag bits used for FFI_SYSV_TYPE_SMALL_STRUCT.
|
||||
Adjust copyright notice.
|
||||
* src/powerpc/ffi.c: Add two new flags to indicate if we have one
|
||||
register or two register to use for FFI_SYSV structs.
|
||||
(ffi_prep_cif_machdep): Pass the right register flag introduced above.
|
||||
(ffi_closure_helper_SYSV): Fix the return type for
|
||||
FFI_SYSV_TYPE_SMALL_STRUCT. Comment.
|
||||
Adjust copyright notice.
|
||||
|
||||
2008-07-16 Kaz Kojima <kkojima@gcc.gnu.org>
|
||||
|
||||
* src/sh/ffi.c (ffi_prep_closure_loc): Turn INSN into an unsigned
|
||||
int.
|
||||
|
||||
2008-03-26 Kaz Kojima <kkojima@gcc.gnu.org>
|
||||
|
||||
* src/sh/sysv.S: Add .note.GNU-stack on Linux.
|
||||
* src/sh64/sysv.S: Likewise.
|
||||
|
||||
2008-03-26 Daniel Jacobowitz <dan@debian.org>
|
||||
|
||||
* src/arm/sysv.S: Fix ARM comment marker.
|
||||
|
||||
2008-03-26 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* src/alpha/osf.S: Add .note.GNU-stack on Linux.
|
||||
* src/s390/sysv.S: Likewise.
|
||||
* src/powerpc/ppc_closure.S: Likewise.
|
||||
* src/powerpc/sysv.S: Likewise.
|
||||
* src/x86/unix64.S: Likewise.
|
||||
* src/x86/sysv.S: Likewise.
|
||||
* src/sparc/v8.S: Likewise.
|
||||
* src/sparc/v9.S: Likewise.
|
||||
* src/m68k/sysv.S: Likewise.
|
||||
* src/arm/sysv.S: Likewise.
|
||||
|
||||
2008-02-12 Bjoern Koenig <bkoenig@alpha-tierchen.de>
|
||||
Andreas Tobler <a.tobler@schweiz.org>
|
||||
|
||||
* configure.ac: Add amd64-*-freebsd* target.
|
||||
* configure: Regenerate.
|
||||
|
||||
2008-01-30 H.J. Lu <hongjiu.lu@intel.com>
|
||||
|
||||
PR libffi/34612
|
||||
* src/x86/sysv.S (ffi_closure_SYSV): Pop 4 byte from stack when
|
||||
returning struct.
|
||||
|
||||
* testsuite/libffi.call/call.exp: Add "-O2 -fomit-frame-pointer"
|
||||
tests.
|
||||
|
||||
2008-01-24 David Edelsohn <edelsohn@gnu.org>
|
||||
|
||||
* configure: Regenerate.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
This is doc/libffi.info, produced by makeinfo version 4.13 from
|
||||
This is doc/libffi.info, produced by makeinfo version 4.12 from
|
||||
./doc/libffi.texi.
|
||||
|
||||
This manual is for Libffi, a portable foreign-function interface
|
||||
@@ -510,8 +510,8 @@ Index
|
||||
* ffi_type_ushort: Primitive Types. (line 53)
|
||||
* ffi_type_void: Primitive Types. (line 10)
|
||||
* Foreign Function Interface: Introduction. (line 31)
|
||||
* void <1>: The Basics. (line 43)
|
||||
* void: The Closure API. (line 27)
|
||||
* void <1>: The Closure API. (line 20)
|
||||
* void: The Basics. (line 43)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -14,14 +14,14 @@
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
#define LIBFFI_ASM
|
||||
|
||||
@@ -14,14 +14,14 @@
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
#define LIBFFI_ASM
|
||||
|
||||
@@ -43,11 +43,12 @@ enum {
|
||||
FLAG_RETURNS_64BITS = 1 << (31-28),
|
||||
|
||||
FLAG_RETURNS_128BITS = 1 << (31-27), /* cr6 */
|
||||
FLAG_SYSV_SMST_R4 = 1 << (31-26), /* use r4 for FFI_SYSV 8 byte
|
||||
structs. */
|
||||
FLAG_SYSV_SMST_R3 = 1 << (31-25), /* use r3 for FFI_SYSV 4 byte
|
||||
structs. */
|
||||
/* Bits (31-24) through (31-19) store shift value for SMST */
|
||||
|
||||
FLAG_SYSV_SMST_R4 = 1 << (31-16), /* cr4, use r4 for FFI_SYSV 8 byte
|
||||
structs. */
|
||||
FLAG_SYSV_SMST_R3 = 1 << (31-15), /* cr3, use r3 for FFI_SYSV 4 byte
|
||||
structs. */
|
||||
FLAG_ARG_NEEDS_COPY = 1 << (31- 7),
|
||||
FLAG_FP_ARGUMENTS = 1 << (31- 6), /* cr1.eq; specified by ABI */
|
||||
FLAG_4_GPR_ARGUMENTS = 1 << (31- 5),
|
||||
@@ -685,14 +686,14 @@ ffi_prep_cif_machdep (ffi_cif *cif)
|
||||
if (size <= 4)
|
||||
{
|
||||
flags |= FLAG_SYSV_SMST_R3;
|
||||
flags |= 8 * (4 - size) << 4;
|
||||
flags |= 8 * (4 - size) << 8;
|
||||
break;
|
||||
}
|
||||
/* These structs are returned in r3 and r4. See above. */
|
||||
if (size <= 8)
|
||||
{
|
||||
flags |= FLAG_SYSV_SMST_R4;
|
||||
flags |= 8 * (8 - size) << 4;
|
||||
flags |= FLAG_SYSV_SMST_R3 | FLAG_SYSV_SMST_R4;
|
||||
flags |= 8 * (8 - size) << 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,12 +95,12 @@ typedef enum ffi_abi {
|
||||
/* For additional types like the below, take care about the order in
|
||||
ppc_closures.S. They must follow after the FFI_TYPE_LAST. */
|
||||
|
||||
/* Needed for soft-float long-double-128 support. */
|
||||
#define FFI_TYPE_UINT128 (FFI_TYPE_LAST + 1)
|
||||
|
||||
/* Needed for FFI_SYSV small structure returns.
|
||||
We use two flag bits, (FLAG_SYSV_SMST_R3, FLAG_SYSV_SMST_R4) which are
|
||||
defined in ffi.c, to determine the exact return type and its size. */
|
||||
#define FFI_TYPE_UINT128 (FFI_TYPE_LAST + 1)
|
||||
|
||||
/* Needed for FFI_SYSV small structure returns. */
|
||||
#define FFI_SYSV_TYPE_SMALL_STRUCT (FFI_TYPE_LAST + 2)
|
||||
|
||||
#if defined(POWERPC64) || defined(POWERPC_AIX)
|
||||
|
||||
@@ -136,29 +136,18 @@ L(float_return_value):
|
||||
b L(done_return_value)
|
||||
|
||||
L(small_struct_return_value):
|
||||
mtcrf 0x10,%r31 /* cr3 */
|
||||
bt- 15,L(smst_one_register)
|
||||
mtcrf 0x08,%r31 /* cr4 */
|
||||
bt- 16,L(smst_two_register)
|
||||
b L(done_return_value)
|
||||
|
||||
L(smst_one_register):
|
||||
rlwinm %r5,%r31,5+23,32-5,31 /* Extract the value to shift. */
|
||||
slw %r3,%r3,%r5
|
||||
stw %r3,0(%r30)
|
||||
b L(done_return_value)
|
||||
L(smst_two_register):
|
||||
rlwinm %r5,%r31,5+23,32-5,31 /* Extract the value to shift. */
|
||||
cmpwi %r5,0
|
||||
subfic %r9,%r5,32
|
||||
slw %r29,%r3,%r5
|
||||
srw %r9,%r4,%r9
|
||||
beq- L(smst_8byte)
|
||||
or %r3,%r9,%r29
|
||||
slw %r4,%r4,%r5
|
||||
L(smst_8byte):
|
||||
stw %r3,0(%r30)
|
||||
stw %r4,4(%r30)
|
||||
extrwi %r6,%r31,2,19 /* number of bytes padding = shift/8 */
|
||||
mtcrf 0x02,%r31 /* copy flags to cr[24:27] (cr6) */
|
||||
extrwi %r5,%r31,5,19 /* r5 <- number of bits of padding */
|
||||
subfic %r6,%r6,4 /* r6 <- number of useful bytes in r3 */
|
||||
bf- 25,L(done_return_value) /* struct in r3 ? if not, done. */
|
||||
/* smst_one_register: */
|
||||
slw %r3,%r3,%r5 /* Left-justify value in r3 */
|
||||
mtxer %r6 /* move byte count to XER ... */
|
||||
stswx %r3,0,%r30 /* ... and store that many bytes */
|
||||
bf+ 26,L(done_return_value) /* struct in r3:r4 ? */
|
||||
add %r6,%r6,%r30 /* adjust pointer */
|
||||
stswi %r4,%r6,4 /* store last four bytes */
|
||||
b L(done_return_value)
|
||||
|
||||
.LFE1:
|
||||
|
||||
@@ -39,11 +39,9 @@ static ffi_status initialize_aggregate(ffi_type *arg)
|
||||
|
||||
FFI_ASSERT(arg != NULL);
|
||||
|
||||
FFI_ASSERT(arg->elements != NULL);
|
||||
FFI_ASSERT(arg->size == 0);
|
||||
|
||||
if (arg->elements == NULL || arg->alignment != 0) {
|
||||
return FFI_BAD_TYPEDEF;
|
||||
}
|
||||
FFI_ASSERT(arg->alignment == 0);
|
||||
|
||||
ptr = &(arg->elements[0]);
|
||||
|
||||
@@ -95,13 +93,7 @@ ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs,
|
||||
ffi_type **ptr;
|
||||
|
||||
FFI_ASSERT(cif != NULL);
|
||||
|
||||
// FIXME: most targets have a broken definition of FFI_LAST_ABI
|
||||
/*
|
||||
if (abi <= FFI_FIRST_ABI || abi >= FFI_LAST_ABI) {
|
||||
return FFI_BAD_ABI;
|
||||
}
|
||||
*/
|
||||
FFI_ASSERT((abi > FFI_FIRST_ABI) && (abi <= FFI_DEFAULT_ABI));
|
||||
|
||||
cif->abi = abi;
|
||||
cif->arg_types = atypes;
|
||||
|
||||
@@ -14,14 +14,14 @@
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
#define LIBFFI_ASM
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
ffi.c - Copyright (c) 2003, 2004 Kaz Kojima
|
||||
ffi.c - Copyright (c) 2003, 2004, 2006, 2007 Kaz Kojima
|
||||
Copyright (c) 2008 Anthony Green
|
||||
|
||||
SuperH SHmedia Foreign Function Interface
|
||||
@@ -56,9 +56,7 @@ return_type (ffi_type *arg)
|
||||
/* ffi_prep_args is called by the assembly routine once stack space
|
||||
has been allocated for the function's arguments */
|
||||
|
||||
/*@-exportheader@*/
|
||||
void ffi_prep_args(char *stack, extended_cif *ecif)
|
||||
/*@=exportheader@*/
|
||||
{
|
||||
register unsigned int i;
|
||||
register unsigned int avn;
|
||||
@@ -162,6 +160,7 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
||||
int n, m;
|
||||
int greg;
|
||||
int freg;
|
||||
int fpair = -1;
|
||||
|
||||
greg = (return_type (cif->rtype) == FFI_TYPE_STRUCT ? 1 : 0);
|
||||
freg = 0;
|
||||
@@ -177,7 +176,13 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
||||
cif->bytes += sizeof (UINT64) - sizeof (float);
|
||||
if (freg >= NFREGARG - 1)
|
||||
continue;
|
||||
freg++;
|
||||
if (fpair < 0)
|
||||
{
|
||||
fpair = freg;
|
||||
freg += 2;
|
||||
}
|
||||
else
|
||||
fpair = -1;
|
||||
cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
|
||||
break;
|
||||
|
||||
@@ -186,7 +191,6 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
||||
continue;
|
||||
if ((freg + 1) < NFREGARG)
|
||||
{
|
||||
freg = (freg + 1) & ~1;
|
||||
freg += 2;
|
||||
cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
|
||||
}
|
||||
@@ -264,9 +268,7 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif,
|
||||
else if ((rvalue == NULL) &&
|
||||
(cif->rtype->type == FFI_TYPE_STRUCT))
|
||||
{
|
||||
/*@-sysunrecog@*/
|
||||
ecif.rvalue = alloca(cif->rtype->size);
|
||||
/*@=sysunrecog@*/
|
||||
}
|
||||
else
|
||||
ecif.rvalue = rvalue;
|
||||
@@ -274,10 +276,8 @@ void ffi_call(/*@dependent@*/ ffi_cif *cif,
|
||||
switch (cif->abi)
|
||||
{
|
||||
case FFI_SYSV:
|
||||
/*@-usedef@*/
|
||||
ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes,
|
||||
cif->flags, cif->flags2, ecif.rvalue, fn);
|
||||
/*@=usedef@*/
|
||||
ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, cif->flags2,
|
||||
ecif.rvalue, fn);
|
||||
break;
|
||||
default:
|
||||
FFI_ASSERT(0);
|
||||
@@ -294,10 +294,11 @@ extern void ffi_closure_SYSV (void);
|
||||
extern void __ic_invalidate (void *line);
|
||||
|
||||
ffi_status
|
||||
ffi_prep_closure (ffi_closure *closure,
|
||||
ffi_cif *cif,
|
||||
void (*fun)(ffi_cif*, void*, void**, void*),
|
||||
void *user_data)
|
||||
ffi_prep_closure_loc (ffi_closure *closure,
|
||||
ffi_cif *cif,
|
||||
void (*fun)(ffi_cif*, void*, void**, void*),
|
||||
void *user_data,
|
||||
void *codeloc)
|
||||
{
|
||||
unsigned int *tramp;
|
||||
|
||||
@@ -321,8 +322,8 @@ ffi_prep_closure (ffi_closure *closure,
|
||||
tramp[2] = 0xcc000010 | (((UINT32) ffi_closure_SYSV) >> 16) << 10;
|
||||
tramp[3] = 0xc8000010 | (((UINT32) ffi_closure_SYSV) & 0xffff) << 10;
|
||||
tramp[4] = 0x6bf10600;
|
||||
tramp[5] = 0xcc000010 | (((UINT32) closure) >> 16) << 10;
|
||||
tramp[6] = 0xc8000010 | (((UINT32) closure) & 0xffff) << 10;
|
||||
tramp[5] = 0xcc000010 | (((UINT32) codeloc) >> 16) << 10;
|
||||
tramp[6] = 0xc8000010 | (((UINT32) codeloc) & 0xffff) << 10;
|
||||
tramp[7] = 0x4401fff0;
|
||||
|
||||
closure->cif = cif;
|
||||
@@ -330,7 +331,8 @@ ffi_prep_closure (ffi_closure *closure,
|
||||
closure->user_data = user_data;
|
||||
|
||||
/* Flush the icache. */
|
||||
asm volatile ("ocbwb %0,0; synco; icbi %0,0; synci" : : "r" (tramp));
|
||||
asm volatile ("ocbwb %0,0; synco; icbi %1,0; synci" : : "r" (tramp),
|
||||
"r"(codeloc));
|
||||
|
||||
return FFI_OK;
|
||||
}
|
||||
@@ -352,6 +354,7 @@ ffi_closure_helper_SYSV (ffi_closure *closure, UINT64 *rvalue,
|
||||
int i, avn;
|
||||
int greg, freg;
|
||||
ffi_cif *cif;
|
||||
int fpair = -1;
|
||||
|
||||
cif = closure->cif;
|
||||
avalue = alloca (cif->nargs * sizeof (void *));
|
||||
@@ -360,7 +363,7 @@ ffi_closure_helper_SYSV (ffi_closure *closure, UINT64 *rvalue,
|
||||
returns the data directly to the caller. */
|
||||
if (return_type (cif->rtype) == FFI_TYPE_STRUCT)
|
||||
{
|
||||
rvalue = *pgr;
|
||||
rvalue = (UINT64 *) *pgr;
|
||||
greg = 1;
|
||||
}
|
||||
else
|
||||
@@ -404,11 +407,24 @@ ffi_closure_helper_SYSV (ffi_closure *closure, UINT64 *rvalue,
|
||||
if ((*p_arg)->type == FFI_TYPE_FLOAT)
|
||||
{
|
||||
if (freg < NFREGARG - 1)
|
||||
{
|
||||
if (fpair >= 0)
|
||||
{
|
||||
avalue[i] = (UINT32 *) pfr + fpair;
|
||||
fpair = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
avalue[i] = (UINT32 *) pfr + (1 ^ freg++);
|
||||
fpair = freg;
|
||||
avalue[i] = (UINT32 *) pfr + (1 ^ freg);
|
||||
#else
|
||||
avalue[i] = (UINT32 *) pfr + freg++;
|
||||
fpair = 1 ^ freg;
|
||||
avalue[i] = (UINT32 *) pfr + freg;
|
||||
#endif
|
||||
freg += 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
avalue[i] = pgr + greg;
|
||||
@@ -430,7 +446,6 @@ ffi_closure_helper_SYSV (ffi_closure *closure, UINT64 *rvalue,
|
||||
avalue[i] = pgr + greg;
|
||||
else
|
||||
{
|
||||
freg = (freg + 1) & ~1;
|
||||
avalue[i] = pfr + (freg >> 1);
|
||||
freg += 2;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
sysv.S - Copyright (c) 2003, 2004, 2008 Kaz Kojima
|
||||
sysv.S - Copyright (c) 2003, 2004, 2006, 2008 Kaz Kojima
|
||||
|
||||
SuperH SHmedia Foreign Function Interface
|
||||
|
||||
@@ -14,14 +14,15 @@
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
#define LIBFFI_ASM
|
||||
@@ -85,6 +86,7 @@ ENTRY(ffi_call_SYSV)
|
||||
addi r15, 64, r22
|
||||
movi 0, r0
|
||||
movi 0, r1
|
||||
movi -1, r23
|
||||
|
||||
pt/l 1f, tr1
|
||||
bnei/l r29, FFI_TYPE_STRUCT, tr1
|
||||
@@ -107,9 +109,6 @@ ENTRY(ffi_call_SYSV)
|
||||
|
||||
.L_pass_d:
|
||||
addi r0, 1, r0
|
||||
addi r1, 1, r1
|
||||
andi r1, ~1, r1
|
||||
|
||||
pt/l 3f, tr0
|
||||
movi 12, r20
|
||||
bge/l r1, r20, tr0
|
||||
@@ -159,13 +158,23 @@ ENTRY(ffi_call_SYSV)
|
||||
addi.l r15, 8, r15
|
||||
3:
|
||||
pt/l .L_pass, tr0
|
||||
addi r1, 1, r1
|
||||
blink tr0, r63
|
||||
|
||||
.L_pop_f:
|
||||
pt/l .L_pop_f_tbl, tr1
|
||||
pt/l 5f, tr2
|
||||
gettr tr1, r20
|
||||
bge/l r23, r63, tr2
|
||||
add r1, r63, r23
|
||||
shlli r1, 3, r21
|
||||
addi r1, 2, r1
|
||||
add r20, r21, r20
|
||||
ptabs/l r20, tr1
|
||||
blink tr1, r63
|
||||
5:
|
||||
addi r23, 1, r21
|
||||
movi -1, r23
|
||||
shlli r21, 3, r21
|
||||
add r20, r21, r20
|
||||
ptabs/l r20, tr1
|
||||
blink tr1, r63
|
||||
|
||||
@@ -308,14 +308,24 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
|
||||
cif->flags = FFI_TYPE_STRUCT;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_SINT8:
|
||||
case FFI_TYPE_UINT8:
|
||||
case FFI_TYPE_SINT16:
|
||||
case FFI_TYPE_UINT16:
|
||||
if (cif->abi == FFI_V9)
|
||||
cif->flags = FFI_TYPE_INT;
|
||||
else
|
||||
cif->flags = cif->rtype->type;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_SINT64:
|
||||
case FFI_TYPE_UINT64:
|
||||
if (cif->abi != FFI_V9)
|
||||
{
|
||||
cif->flags = FFI_TYPE_SINT64;
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
if (cif->abi == FFI_V9)
|
||||
cif->flags = FFI_TYPE_INT;
|
||||
else
|
||||
cif->flags = FFI_TYPE_SINT64;
|
||||
break;
|
||||
|
||||
default:
|
||||
cif->flags = FFI_TYPE_INT;
|
||||
break;
|
||||
|
||||
@@ -73,21 +73,63 @@ _ffi_call_v8:
|
||||
be,a done
|
||||
st %f0, [%i4+0] ! (delay)
|
||||
|
||||
cmp %i3, FFI_TYPE_SINT64
|
||||
be longlong
|
||||
|
||||
cmp %i3, FFI_TYPE_DOUBLE
|
||||
bne done
|
||||
nop
|
||||
st %f0, [%i4+0]
|
||||
st %f1, [%i4+4]
|
||||
|
||||
be,a double
|
||||
st %f0, [%i4+0] ! (delay)
|
||||
|
||||
cmp %i3, FFI_TYPE_SINT8
|
||||
be,a sint8
|
||||
sll %o0, 24, %o0 ! (delay)
|
||||
|
||||
cmp %i3, FFI_TYPE_UINT8
|
||||
be,a uint8
|
||||
sll %o0, 24, %o0 ! (delay)
|
||||
|
||||
cmp %i3, FFI_TYPE_SINT16
|
||||
be,a sint16
|
||||
sll %o0, 16, %o0 ! (delay)
|
||||
|
||||
cmp %i3, FFI_TYPE_UINT16
|
||||
be,a uint16
|
||||
sll %o0, 16, %o0 ! (delay)
|
||||
|
||||
cmp %i3, FFI_TYPE_SINT64
|
||||
be,a longlong
|
||||
st %o0, [%i4+0] ! (delay)
|
||||
done:
|
||||
ret
|
||||
restore
|
||||
|
||||
longlong:
|
||||
double:
|
||||
st %f1, [%i4+4]
|
||||
ret
|
||||
restore
|
||||
|
||||
sint8:
|
||||
sra %o0, 24, %o0
|
||||
st %o0, [%i4+0]
|
||||
ret
|
||||
restore
|
||||
|
||||
uint8:
|
||||
srl %o0, 24, %o0
|
||||
st %o0, [%i4+0]
|
||||
ret
|
||||
restore
|
||||
|
||||
sint16:
|
||||
sra %o0, 16, %o0
|
||||
st %o0, [%i4+0]
|
||||
ret
|
||||
restore
|
||||
|
||||
uint16:
|
||||
srl %o0, 16, %o0
|
||||
st %o0, [%i4+0]
|
||||
ret
|
||||
restore
|
||||
|
||||
longlong:
|
||||
st %o1, [%i4+4]
|
||||
ret
|
||||
restore
|
||||
@@ -148,7 +190,8 @@ ffi_closure_v8:
|
||||
be done1
|
||||
|
||||
cmp %o0, FFI_TYPE_INT
|
||||
be integer
|
||||
be done1
|
||||
ld [%fp-8], %i0
|
||||
|
||||
cmp %o0, FFI_TYPE_FLOAT
|
||||
be,a done1
|
||||
@@ -166,13 +209,11 @@ ffi_closure_v8:
|
||||
cmp %o0, FFI_TYPE_STRUCT
|
||||
be done2
|
||||
|
||||
! FFI_TYPE_SINT64
|
||||
! FFI_TYPE_UINT64
|
||||
ld [%fp-4], %i1
|
||||
cmp %o0, FFI_TYPE_SINT64
|
||||
be,a done1
|
||||
ldd [%fp-8], %i0
|
||||
|
||||
integer:
|
||||
ld [%fp-8], %i0
|
||||
|
||||
done1:
|
||||
jmp %i7+8
|
||||
restore
|
||||
|
||||
@@ -15,15 +15,16 @@
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
----------------------------------------------------------------------- */
|
||||
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef __x86_64__
|
||||
|
||||
|
||||
@@ -277,16 +277,16 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
|
||||
/* value address then we need to make one */
|
||||
|
||||
#ifdef X86_WIN64
|
||||
if ((rvalue == NULL) &&
|
||||
(cif->flags == FFI_TYPE_STRUCT
|
||||
&& cif->rtype->size != 1 && cif->rtype->size != 2
|
||||
&& cif->rtype->size != 4 && cif->rtype->size != 8))
|
||||
if (rvalue == NULL
|
||||
&& cif->flags == FFI_TYPE_STRUCT
|
||||
&& cif->rtype->size != 1 && cif->rtype->size != 2
|
||||
&& cif->rtype->size != 4 && cif->rtype->size != 8)
|
||||
{
|
||||
ecif.rvalue = alloca((cif->rtype->size + 0xF) & ~0xF);
|
||||
}
|
||||
#else
|
||||
if ((rvalue == NULL) &&
|
||||
cif->flags == FFI_TYPE_STRUCT)
|
||||
if (rvalue == NULL
|
||||
&& cif->flags == FFI_TYPE_STRUCT)
|
||||
{
|
||||
ecif.rvalue = alloca(cif->rtype->size);
|
||||
}
|
||||
@@ -450,7 +450,7 @@ ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue,
|
||||
size_t z;
|
||||
|
||||
/* Align if necessary */
|
||||
if ((sizeof(void *) - 1) & (size_t) argp) {
|
||||
if ((sizeof(void*) - 1) & (size_t) argp) {
|
||||
argp = (char *) ALIGN(argp, sizeof(void*));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
win32.S - Copyright (c) 1996, 1998, 2001, 2002 Red Hat, Inc.
|
||||
win32.S - Copyright (c) 1996, 1998, 2001, 2002, 2009 Red Hat, Inc.
|
||||
Copyright (c) 2001 John Beniton
|
||||
Copyright (c) 2002 Ranjit Mathew
|
||||
|
||||
@@ -17,30 +17,33 @@
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
----------------------------------------------------------------------- */
|
||||
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define LIBFFI_ASM
|
||||
#include <fficonfig.h>
|
||||
#include <ffi.h>
|
||||
|
||||
.text
|
||||
.text
|
||||
|
||||
# This assumes we are using gas.
|
||||
.balign 16
|
||||
.globl _ffi_call_SYSV
|
||||
|
||||
.globl _ffi_call_SYSV
|
||||
.def _ffi_call_SYSV; .scl 2; .type 32; .endef
|
||||
_ffi_call_SYSV:
|
||||
.LFB1:
|
||||
pushl %ebp
|
||||
.LCFI0:
|
||||
movl %esp,%ebp
|
||||
|
||||
.LCFI1:
|
||||
# Make room for all of the new args.
|
||||
movl 16(%ebp),%ecx
|
||||
subl %ecx,%esp
|
||||
@@ -143,17 +146,19 @@ epilogue:
|
||||
movl %ebp,%esp
|
||||
popl %ebp
|
||||
ret
|
||||
|
||||
.ffi_call_SYSV_end:
|
||||
.LFE1:
|
||||
|
||||
# This assumes we are using gas.
|
||||
.balign 16
|
||||
.globl _ffi_call_STDCALL
|
||||
|
||||
.globl _ffi_call_STDCALL
|
||||
.def _ffi_call_STDCALL; .scl 2; .type 32; .endef
|
||||
_ffi_call_STDCALL:
|
||||
.LFB2:
|
||||
pushl %ebp
|
||||
.LCFI2:
|
||||
movl %esp,%ebp
|
||||
|
||||
.LCFI3:
|
||||
# Make room for all of the new args.
|
||||
movl 16(%ebp),%ecx
|
||||
subl %ecx,%esp
|
||||
@@ -254,29 +259,19 @@ sc_epilogue:
|
||||
movl %ebp,%esp
|
||||
popl %ebp
|
||||
ret
|
||||
|
||||
.ffi_call_STDCALL_end:
|
||||
.LFE2:
|
||||
|
||||
.globl _ffi_closure_STDCALL
|
||||
_ffi_closure_STDCALL:
|
||||
pushl %ebp
|
||||
movl %esp, %ebp
|
||||
subl $40, %esp
|
||||
leal -24(%ebp), %edx
|
||||
movl %edx, -12(%ebp) /* resp */
|
||||
leal 12(%ebp), %edx /* account for stub return address on stack */
|
||||
movl %edx, 4(%esp) /* args */
|
||||
leal -12(%ebp), %edx
|
||||
movl %edx, (%esp) /* &resp */
|
||||
call _ffi_closure_SYSV_inner
|
||||
movl -12(%ebp), %ecx
|
||||
jmp .Lcls_return_result
|
||||
.ffi_closure_STDCALL_end:
|
||||
|
||||
.globl _ffi_closure_SYSV
|
||||
# This assumes we are using gas.
|
||||
.balign 16
|
||||
.globl _ffi_closure_SYSV
|
||||
.def _ffi_closure_SYSV; .scl 2; .type 32; .endef
|
||||
_ffi_closure_SYSV:
|
||||
.LFB3:
|
||||
pushl %ebp
|
||||
.LCFI4:
|
||||
movl %esp, %ebp
|
||||
.LCFI5:
|
||||
subl $40, %esp
|
||||
leal -24(%ebp), %edx
|
||||
movl %edx, -12(%ebp) /* resp */
|
||||
@@ -286,7 +281,6 @@ _ffi_closure_SYSV:
|
||||
movl %edx, (%esp) /* &resp */
|
||||
call _ffi_closure_SYSV_inner
|
||||
movl -12(%ebp), %ecx
|
||||
.Lcls_return_result:
|
||||
cmpl $FFI_TYPE_INT, %eax
|
||||
je .Lcls_retint
|
||||
cmpl $FFI_TYPE_FLOAT, %eax
|
||||
@@ -328,6 +322,7 @@ _ffi_closure_SYSV:
|
||||
movswl (%ecx), %eax
|
||||
jmp .Lcls_epilogue
|
||||
.ffi_closure_SYSV_end:
|
||||
.LFE3:
|
||||
|
||||
#if !FFI_NO_RAW_API
|
||||
|
||||
@@ -336,12 +331,18 @@ _ffi_closure_SYSV:
|
||||
#define RAW_CLOSURE_USER_DATA_OFFSET (RAW_CLOSURE_FUN_OFFSET + 4)
|
||||
#define CIF_FLAGS_OFFSET 20
|
||||
|
||||
.balign 16
|
||||
.globl _ffi_closure_raw_SYSV
|
||||
# This assumes we are using gas.
|
||||
.balign 16
|
||||
.globl _ffi_closure_raw_SYSV
|
||||
.def _ffi_closure_raw_SYSV; .scl 2; .type 32; .endef
|
||||
_ffi_closure_raw_SYSV:
|
||||
.LFB4:
|
||||
pushl %ebp
|
||||
.LCFI6:
|
||||
movl %esp, %ebp
|
||||
.LCFI7:
|
||||
pushl %esi
|
||||
.LCFI8:
|
||||
subl $36, %esp
|
||||
movl RAW_CLOSURE_CIF_OFFSET(%eax), %esi /* closure->cif */
|
||||
movl RAW_CLOSURE_USER_DATA_OFFSET(%eax), %edx /* closure->user_data */
|
||||
@@ -385,5 +386,264 @@ _ffi_closure_raw_SYSV:
|
||||
movl -20(%ebp), %edx
|
||||
jmp .Lrcls_epilogue
|
||||
.ffi_closure_raw_SYSV_end:
|
||||
.LFE4:
|
||||
|
||||
#endif /* !FFI_NO_RAW_API */
|
||||
|
||||
# This assumes we are using gas.
|
||||
.balign 16
|
||||
.globl _ffi_closure_STDCALL
|
||||
.def _ffi_closure_STDCALL; .scl 2; .type 32; .endef
|
||||
_ffi_closure_STDCALL:
|
||||
.LFB5:
|
||||
pushl %ebp
|
||||
.LCFI9:
|
||||
movl %esp, %ebp
|
||||
.LCFI10:
|
||||
subl $40, %esp
|
||||
leal -24(%ebp), %edx
|
||||
movl %edx, -12(%ebp) /* resp */
|
||||
leal 12(%ebp), %edx /* account for stub return address on stack */
|
||||
movl %edx, 4(%esp) /* args */
|
||||
leal -12(%ebp), %edx
|
||||
movl %edx, (%esp) /* &resp */
|
||||
call _ffi_closure_SYSV_inner
|
||||
movl -12(%ebp), %ecx
|
||||
/* It would be nice to just share this code with the
|
||||
duplicate sequence in _ffi_closure_SYSV, if only
|
||||
there were some way to represent that in the EH info. */
|
||||
cmpl $FFI_TYPE_INT, %eax
|
||||
je .Lscls_retint
|
||||
cmpl $FFI_TYPE_FLOAT, %eax
|
||||
je .Lscls_retfloat
|
||||
cmpl $FFI_TYPE_DOUBLE, %eax
|
||||
je .Lscls_retdouble
|
||||
cmpl $FFI_TYPE_LONGDOUBLE, %eax
|
||||
je .Lscls_retldouble
|
||||
cmpl $FFI_TYPE_SINT64, %eax
|
||||
je .Lscls_retllong
|
||||
cmpl $FFI_TYPE_SINT8, %eax /* 1-byte struct */
|
||||
je .Lscls_retstruct1
|
||||
cmpl $FFI_TYPE_SINT16, %eax /* 2-bytes struct */
|
||||
je .Lscls_retstruct2
|
||||
.Lscls_epilogue:
|
||||
movl %ebp, %esp
|
||||
popl %ebp
|
||||
ret
|
||||
.Lscls_retint:
|
||||
movl (%ecx), %eax
|
||||
jmp .Lscls_epilogue
|
||||
.Lscls_retfloat:
|
||||
flds (%ecx)
|
||||
jmp .Lscls_epilogue
|
||||
.Lscls_retdouble:
|
||||
fldl (%ecx)
|
||||
jmp .Lscls_epilogue
|
||||
.Lscls_retldouble:
|
||||
fldt (%ecx)
|
||||
jmp .Lscls_epilogue
|
||||
.Lscls_retllong:
|
||||
movl (%ecx), %eax
|
||||
movl 4(%ecx), %edx
|
||||
jmp .Lscls_epilogue
|
||||
.Lscls_retstruct1:
|
||||
movsbl (%ecx), %eax
|
||||
jmp .Lscls_epilogue
|
||||
.Lscls_retstruct2:
|
||||
movswl (%ecx), %eax
|
||||
jmp .Lscls_epilogue
|
||||
.ffi_closure_STDCALL_end:
|
||||
.LFE5:
|
||||
|
||||
.section .eh_frame,"w"
|
||||
.Lframe1:
|
||||
.LSCIE1:
|
||||
.long .LECIE1-.LASCIE1 /* Length of Common Information Entry */
|
||||
.LASCIE1:
|
||||
.long 0x0 /* CIE Identifier Tag */
|
||||
.byte 0x1 /* CIE Version */
|
||||
#ifdef __PIC__
|
||||
.ascii "zR\0" /* CIE Augmentation */
|
||||
#else
|
||||
.ascii "\0" /* CIE Augmentation */
|
||||
#endif
|
||||
.byte 0x1 /* .uleb128 0x1; CIE Code Alignment Factor */
|
||||
.byte 0x7c /* .sleb128 -4; CIE Data Alignment Factor */
|
||||
.byte 0x8 /* CIE RA Column */
|
||||
#ifdef __PIC__
|
||||
.byte 0x1 /* .uleb128 0x1; Augmentation size */
|
||||
.byte 0x1b /* FDE Encoding (pcrel sdata4) */
|
||||
#endif
|
||||
.byte 0xc /* DW_CFA_def_cfa CFA = r4 + 4 = 4(%esp) */
|
||||
.byte 0x4 /* .uleb128 0x4 */
|
||||
.byte 0x4 /* .uleb128 0x4 */
|
||||
.byte 0x88 /* DW_CFA_offset, column 0x8 %eip at CFA + 1 * -4 */
|
||||
.byte 0x1 /* .uleb128 0x1 */
|
||||
.align 4
|
||||
.LECIE1:
|
||||
|
||||
.LSFDE1:
|
||||
.long .LEFDE1-.LASFDE1 /* FDE Length */
|
||||
.LASFDE1:
|
||||
.long .LASFDE1-.Lframe1 /* FDE CIE offset */
|
||||
#if defined __PIC__ && defined HAVE_AS_X86_PCREL
|
||||
.long .LFB1-. /* FDE initial location */
|
||||
#else
|
||||
.long .LFB1
|
||||
#endif
|
||||
.long .LFE1-.LFB1 /* FDE address range */
|
||||
#ifdef __PIC__
|
||||
.byte 0x0 /* .uleb128 0x0; Augmentation size */
|
||||
#endif
|
||||
/* DW_CFA_xxx CFI instructions go here. */
|
||||
|
||||
.byte 0x4 /* DW_CFA_advance_loc4 */
|
||||
.long .LCFI0-.LFB1
|
||||
.byte 0xe /* DW_CFA_def_cfa_offset CFA = r4 + 8 = 8(%esp) */
|
||||
.byte 0x8 /* .uleb128 0x8 */
|
||||
.byte 0x85 /* DW_CFA_offset, column 0x5 %ebp at CFA + 2 * -4 */
|
||||
.byte 0x2 /* .uleb128 0x2 */
|
||||
|
||||
.byte 0x4 /* DW_CFA_advance_loc4 */
|
||||
.long .LCFI1-.LCFI0
|
||||
.byte 0xd /* DW_CFA_def_cfa_register CFA = r5 = %ebp */
|
||||
.byte 0x5 /* .uleb128 0x5 */
|
||||
|
||||
/* End of DW_CFA_xxx CFI instructions. */
|
||||
.align 4
|
||||
.LEFDE1:
|
||||
|
||||
|
||||
.LSFDE2:
|
||||
.long .LEFDE2-.LASFDE2 /* FDE Length */
|
||||
.LASFDE2:
|
||||
.long .LASFDE2-.Lframe1 /* FDE CIE offset */
|
||||
#if defined __PIC__ && defined HAVE_AS_X86_PCREL
|
||||
.long .LFB2-. /* FDE initial location */
|
||||
#else
|
||||
.long .LFB2
|
||||
#endif
|
||||
.long .LFE2-.LFB2 /* FDE address range */
|
||||
#ifdef __PIC__
|
||||
.byte 0x0 /* .uleb128 0x0; Augmentation size */
|
||||
#endif
|
||||
/* DW_CFA_xxx CFI instructions go here. */
|
||||
|
||||
.byte 0x4 /* DW_CFA_advance_loc4 */
|
||||
.long .LCFI2-.LFB2
|
||||
.byte 0xe /* DW_CFA_def_cfa_offset CFA = r4 + 8 = 8(%esp) */
|
||||
.byte 0x8 /* .uleb128 0x8 */
|
||||
.byte 0x85 /* DW_CFA_offset, column 0x5 %ebp at CFA + 2 * -4 */
|
||||
.byte 0x2 /* .uleb128 0x2 */
|
||||
|
||||
.byte 0x4 /* DW_CFA_advance_loc4 */
|
||||
.long .LCFI3-.LCFI2
|
||||
.byte 0xd /* DW_CFA_def_cfa_register CFA = r5 = %ebp */
|
||||
.byte 0x5 /* .uleb128 0x5 */
|
||||
|
||||
/* End of DW_CFA_xxx CFI instructions. */
|
||||
.align 4
|
||||
.LEFDE2:
|
||||
|
||||
|
||||
.LSFDE3:
|
||||
.long .LEFDE3-.LASFDE3 /* FDE Length */
|
||||
.LASFDE3:
|
||||
.long .LASFDE3-.Lframe1 /* FDE CIE offset */
|
||||
#if defined __PIC__ && defined HAVE_AS_X86_PCREL
|
||||
.long .LFB3-. /* FDE initial location */
|
||||
#else
|
||||
.long .LFB3
|
||||
#endif
|
||||
.long .LFE3-.LFB3 /* FDE address range */
|
||||
#ifdef __PIC__
|
||||
.byte 0x0 /* .uleb128 0x0; Augmentation size */
|
||||
#endif
|
||||
/* DW_CFA_xxx CFI instructions go here. */
|
||||
|
||||
.byte 0x4 /* DW_CFA_advance_loc4 */
|
||||
.long .LCFI4-.LFB3
|
||||
.byte 0xe /* DW_CFA_def_cfa_offset CFA = r4 + 8 = 8(%esp) */
|
||||
.byte 0x8 /* .uleb128 0x8 */
|
||||
.byte 0x85 /* DW_CFA_offset, column 0x5 %ebp at CFA + 2 * -4 */
|
||||
.byte 0x2 /* .uleb128 0x2 */
|
||||
|
||||
.byte 0x4 /* DW_CFA_advance_loc4 */
|
||||
.long .LCFI5-.LCFI4
|
||||
.byte 0xd /* DW_CFA_def_cfa_register CFA = r5 = %ebp */
|
||||
.byte 0x5 /* .uleb128 0x5 */
|
||||
|
||||
/* End of DW_CFA_xxx CFI instructions. */
|
||||
.align 4
|
||||
.LEFDE3:
|
||||
|
||||
#if !FFI_NO_RAW_API
|
||||
|
||||
.LSFDE4:
|
||||
.long .LEFDE4-.LASFDE4 /* FDE Length */
|
||||
.LASFDE4:
|
||||
.long .LASFDE4-.Lframe1 /* FDE CIE offset */
|
||||
#if defined __PIC__ && defined HAVE_AS_X86_PCREL
|
||||
.long .LFB4-. /* FDE initial location */
|
||||
#else
|
||||
.long .LFB4
|
||||
#endif
|
||||
.long .LFE4-.LFB4 /* FDE address range */
|
||||
#ifdef __PIC__
|
||||
.byte 0x0 /* .uleb128 0x0; Augmentation size */
|
||||
#endif
|
||||
/* DW_CFA_xxx CFI instructions go here. */
|
||||
|
||||
.byte 0x4 /* DW_CFA_advance_loc4 */
|
||||
.long .LCFI6-.LFB4
|
||||
.byte 0xe /* DW_CFA_def_cfa_offset CFA = r4 + 8 = 8(%esp) */
|
||||
.byte 0x8 /* .uleb128 0x8 */
|
||||
.byte 0x85 /* DW_CFA_offset, column 0x5 %ebp at CFA + 2 * -4 */
|
||||
.byte 0x2 /* .uleb128 0x2 */
|
||||
|
||||
.byte 0x4 /* DW_CFA_advance_loc4 */
|
||||
.long .LCFI7-.LCFI6
|
||||
.byte 0xd /* DW_CFA_def_cfa_register CFA = r5 = %ebp */
|
||||
.byte 0x5 /* .uleb128 0x5 */
|
||||
|
||||
.byte 0x4 /* DW_CFA_advance_loc4 */
|
||||
.long .LCFI8-.LCFI7
|
||||
.byte 0x86 /* DW_CFA_offset, column 0x6 %esi at CFA + 3 * -4 */
|
||||
.byte 0x3 /* .uleb128 0x3 */
|
||||
|
||||
/* End of DW_CFA_xxx CFI instructions. */
|
||||
.align 4
|
||||
.LEFDE4:
|
||||
|
||||
#endif /* !FFI_NO_RAW_API */
|
||||
|
||||
.LSFDE5:
|
||||
.long .LEFDE5-.LASFDE5 /* FDE Length */
|
||||
.LASFDE5:
|
||||
.long .LASFDE5-.Lframe1 /* FDE CIE offset */
|
||||
#if defined __PIC__ && defined HAVE_AS_X86_PCREL
|
||||
.long .LFB5-. /* FDE initial location */
|
||||
#else
|
||||
.long .LFB5
|
||||
#endif
|
||||
.long .LFE5-.LFB5 /* FDE address range */
|
||||
#ifdef __PIC__
|
||||
.byte 0x0 /* .uleb128 0x0; Augmentation size */
|
||||
#endif
|
||||
/* DW_CFA_xxx CFI instructions go here. */
|
||||
|
||||
.byte 0x4 /* DW_CFA_advance_loc4 */
|
||||
.long .LCFI9-.LFB5
|
||||
.byte 0xe /* DW_CFA_def_cfa_offset CFA = r4 + 8 = 8(%esp) */
|
||||
.byte 0x8 /* .uleb128 0x8 */
|
||||
.byte 0x85 /* DW_CFA_offset, column 0x5 %ebp at CFA + 2 * -4 */
|
||||
.byte 0x2 /* .uleb128 0x2 */
|
||||
|
||||
.byte 0x4 /* DW_CFA_advance_loc4 */
|
||||
.long .LCFI10-.LCFI9
|
||||
.byte 0xd /* DW_CFA_def_cfa_register CFA = r5 = %ebp */
|
||||
.byte 0x5 /* .uleb128 0x5 */
|
||||
|
||||
/* End of DW_CFA_xxx CFI instructions. */
|
||||
.align 4
|
||||
.LEFDE5:
|
||||
|
||||
@@ -181,6 +181,13 @@ proc libffi_target_compile { source dest type options } {
|
||||
lappend options "additional_flags=-I${libffi_include} -I${srcdir}/../include -I${libffi_include}/.."
|
||||
lappend options "additional_flags=${libffi_link_flags}"
|
||||
|
||||
# Darwin needs a stack execution allowed flag.
|
||||
|
||||
if { [istarget "*-*-darwin9*"] || [istarget "*-*-darwin1*"]
|
||||
|| [istarget "*-*-darwin2*"] } {
|
||||
lappend options "additional_flags=-Wl,-allow_stack_execute"
|
||||
}
|
||||
|
||||
# If you're building the compiler with --prefix set to a place
|
||||
# where it's not yet installed, then the linker won't be able to
|
||||
# find the libgcc used by libffi.dylib. We could pass the
|
||||
|
||||
@@ -22,7 +22,7 @@ cls_struct_align cls_struct_align_fn(struct cls_struct_align a1,
|
||||
result.b = a1.b + a2.b;
|
||||
result.c = a1.c + a2.c;
|
||||
|
||||
printf("%d %" PRId64 " %d %d %" PRId64 " %d: %d %" PRId64 " %d\n", a1.a, a1.b, a1.c, a2.a, a2.b, a2.c, result.a, result.b, result.c);
|
||||
printf("%d %" PRIdLL " %d %d %" PRIdLL " %d: %d %" PRIdLL " %d\n", a1.a, a1.b, a1.c, a2.a, a2.b, a2.c, result.a, result.b, result.c);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -77,14 +77,14 @@ int main (void)
|
||||
|
||||
ffi_call(&cif, FFI_FN(cls_struct_align_fn), &res_dbl, args_dbl);
|
||||
/* { dg-output "12 4951 127 1 9320 13: 13 14271 140" } */
|
||||
printf("res: %d %" PRId64 " %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
|
||||
printf("res: %d %" PRIdLL " %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
|
||||
/* { dg-output "\nres: 13 14271 140" } */
|
||||
|
||||
CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK);
|
||||
|
||||
res_dbl = ((cls_struct_align(*)(cls_struct_align, cls_struct_align))(code))(g_dbl, f_dbl);
|
||||
/* { dg-output "\n12 4951 127 1 9320 13: 13 14271 140" } */
|
||||
printf("res: %d %" PRId64 " %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
|
||||
printf("res: %d %" PRIdLL " %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
|
||||
/* { dg-output "\nres: 13 14271 140" } */
|
||||
|
||||
exit(0);
|
||||
|
||||
@@ -23,7 +23,7 @@ cls_struct_align cls_struct_align_fn(struct cls_struct_align a1,
|
||||
result.b = a1.b + a2.b;
|
||||
result.c = a1.c + a2.c;
|
||||
|
||||
printf("%d %" PRId64 " %d %d %" PRId64 " %d: %d %" PRId64 " %d\n", a1.a, a1.b, a1.c, a2.a, a2.b, a2.c, result.a, result.b, result.c);
|
||||
printf("%d %" PRIdLL " %d %d %" PRIdLL " %d: %d %" PRIdLL " %d\n", a1.a, a1.b, a1.c, a2.a, a2.b, a2.c, result.a, result.b, result.c);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -78,14 +78,14 @@ int main (void)
|
||||
|
||||
ffi_call(&cif, FFI_FN(cls_struct_align_fn), &res_dbl, args_dbl);
|
||||
/* { dg-output "12 4951 127 1 9320 13: 13 14271 140" } */
|
||||
printf("res: %d %" PRId64 " %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
|
||||
printf("res: %d %" PRIdLL " %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
|
||||
/* { dg-output "\nres: 13 14271 140" } */
|
||||
|
||||
CHECK(ffi_prep_closure_loc(pcl, &cif, cls_struct_align_gn, NULL, code) == FFI_OK);
|
||||
|
||||
res_dbl = ((cls_struct_align(*)(cls_struct_align, cls_struct_align))(code))(g_dbl, f_dbl);
|
||||
/* { dg-output "\n12 4951 127 1 9320 13: 13 14271 140" } */
|
||||
printf("res: %d %" PRId64 " %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
|
||||
printf("res: %d %" PRIdLL " %d\n", res_dbl.a, res_dbl.b, res_dbl.c);
|
||||
/* { dg-output "\nres: 13 14271 140" } */
|
||||
|
||||
exit(0);
|
||||
|
||||
@@ -57,7 +57,7 @@ int main(int argc __UNUSED__, char** argv __UNUSED__)
|
||||
CHECK(ffi_prep_closure_loc(pcl, &cif, closure_test_gn, NULL, code) == FFI_OK);
|
||||
|
||||
((void*(*)(Dbls))(code))(arg);
|
||||
/* { dg-output "1.0 2.0\n" } */
|
||||
/* { dg-output "1.0 2.0\n" { xfail x86_64-*-linux-* } } */
|
||||
|
||||
closure_test_fn(arg);
|
||||
/* { dg-output "1.0 2.0\n" } */
|
||||
|
||||
@@ -42,9 +42,9 @@ int main (void)
|
||||
args[2] = NULL;
|
||||
|
||||
ffi_call(&cif, FFI_FN(printf), &res, args);
|
||||
// { dg-output "7.0" }
|
||||
// { dg-output "7.0" { xfail i*86-*-linux-* x86_64-*-linux-* } }
|
||||
printf("res: %d\n", (int) res);
|
||||
// { dg-output "\nres: 4" }
|
||||
// { dg-output "\nres: 4" { xfail i*86-*-linux-* x86_64-*-linux-* } }
|
||||
|
||||
CHECK(ffi_prep_closure_loc(pcl, &cif, cls_longdouble_va_fn, NULL, code) == FFI_OK);
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ static void cls_ret_ulonglong_fn(ffi_cif* cif __UNUSED__, void* resp,
|
||||
{
|
||||
*(unsigned long long *)resp= *(unsigned long long *)args[0];
|
||||
|
||||
printf("%" PRIu64 ": %" PRIu64 "\n",*(unsigned long long *)args[0],
|
||||
printf("%" PRIuLL ": %" PRIuLL "\n",*(unsigned long long *)args[0],
|
||||
*(unsigned long long *)(resp));
|
||||
}
|
||||
typedef unsigned long long (*cls_ret_ulonglong)(unsigned long long);
|
||||
@@ -34,12 +34,12 @@ int main (void)
|
||||
CHECK(ffi_prep_closure_loc(pcl, &cif, cls_ret_ulonglong_fn, NULL, code) == FFI_OK);
|
||||
res = (*((cls_ret_ulonglong)code))(214LL);
|
||||
/* { dg-output "214: 214" } */
|
||||
printf("res: %" PRId64 "\n", res);
|
||||
printf("res: %" PRIdLL "\n", res);
|
||||
/* { dg-output "\nres: 214" } */
|
||||
|
||||
res = (*((cls_ret_ulonglong)code))(9223372035854775808LL);
|
||||
/* { dg-output "\n9223372035854775808: 9223372035854775808" } */
|
||||
printf("res: %" PRId64 "\n", res);
|
||||
printf("res: %" PRIdLL "\n", res);
|
||||
/* { dg-output "\nres: 9223372035854775808" } */
|
||||
|
||||
exit(0);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
PR: none.
|
||||
Originator: Blake Chaffin 6/6/2007 */
|
||||
|
||||
/* { dg-do run { xfail mips*-*-* arm*-*-* strongarm*-*-* xscale*-*-* } } */
|
||||
/* { dg-do run { xfail *-*-* } } */
|
||||
#include "ffitest.h"
|
||||
|
||||
static void
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
PR: none.
|
||||
Originator: Blake Chaffin 6/6/2007 */
|
||||
|
||||
/* { dg-do run { xfail mips*-*-* arm*-*-* strongarm*-*-* xscale*-*-* } } */
|
||||
/* { dg-do run { xfail *-*-* } } */
|
||||
#include "ffitest.h"
|
||||
|
||||
int main (void)
|
||||
|
||||
@@ -45,6 +45,15 @@
|
||||
|
||||
#endif
|
||||
|
||||
/* MinGW kludge. */
|
||||
#ifdef WIN64
|
||||
#define PRIdLL "PRId64"
|
||||
#define PRIuLL "PRIu64"
|
||||
#else
|
||||
#define PRIdLL "lld"
|
||||
#define PRIuLL "llu"
|
||||
#endif
|
||||
|
||||
#ifdef USING_MMAP
|
||||
static inline void *
|
||||
allocate_mmap (size_t size)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
PR: none.
|
||||
Originator: From the original ffitest.c */
|
||||
|
||||
/* { dg-excess-errors { target x86_64-*-mingw* x86_64-*-cygwin* } } */
|
||||
/* { dg-excess-errors "" { target x86_64-*-mingw* x86_64-*-cygwin* } } */
|
||||
/* { dg-do run { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */
|
||||
|
||||
#include "ffitest.h"
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
Originator: Blake Chaffin 6/18/2007
|
||||
*/
|
||||
|
||||
/* { dg-excess-errors { target x86_64-*-mingw* x86_64-*-cygwin* } } */
|
||||
/* { dg-excess-errors "" { target x86_64-*-mingw* x86_64-*-cygwin* i*86-*-linux-* x86_64-*-linux-* } } */
|
||||
/* { dg-do run { xfail mips*-*-* arm*-*-* strongarm*-*-* xscale*-*-* } } */
|
||||
/* { dg-options -mlong-double-128 { target powerpc64*-*-* } } */
|
||||
/* { dg-output "" { xfail x86_64-*-mingw* x86_64-*-cygwin* } } */
|
||||
/* { dg-output "" { xfail x86_64-*-mingw* x86_64-*-cygwin* i*86-*-linux-* x86_64-*-linux-* } } */
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ int main (void)
|
||||
ll2 = 11111111;
|
||||
|
||||
ffi_call(&cif, FFI_FN(return_ll), &rlonglong, values);
|
||||
printf("res: %" PRId64 ", %" PRId64 "\n", rlonglong, ll0 + ll1 + ll2);
|
||||
printf("res: %" PRIdLL ", %" PRIdLL "\n", rlonglong, ll0 + ll1 + ll2);
|
||||
/* { dg-output "res: 11111133333222, 11111133333222" } */
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
PR: none.
|
||||
Originator: Blake Chaffin 6/21/2007 */
|
||||
|
||||
/* { dg-do run { xfail mips*-*-* arm*-*-* strongarm*-*-* xscale*-*-* } } */
|
||||
/* { dg-do run { xfail mips*-*-* arm*-*-* strongarm*-*-* xscale*-*-* } } */
|
||||
#include "ffitest.h"
|
||||
|
||||
// 13 FPRs: 104 bytes
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
PR: none.
|
||||
Originator: Blake Chaffin 6/21/2007 */
|
||||
|
||||
/* { dg-do run { xfail mips*-*-* arm*-*-* strongarm*-*-* xscale*-*-* } } */
|
||||
/* { dg-do run { xfail mips*-*-* arm*-*-* strongarm*-*-* xscale*-*-* } } */
|
||||
#include "ffitest.h"
|
||||
|
||||
// 13 FPRs: 104 bytes
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
PR: none.
|
||||
Originator: Blake Chaffin 6/21/2007 */
|
||||
|
||||
/* { dg-do run { xfail mips*-*-* arm*-*-* strongarm*-*-* xscale*-*-* } } */
|
||||
/* { dg-do run { xfail mips*-*-* arm*-*-* strongarm*-*-* xscale*-*-* } } */
|
||||
#include "ffitest.h"
|
||||
|
||||
typedef struct struct_72byte {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
PR: none.
|
||||
Originator: Blake Chaffin 6/21/2007 */
|
||||
|
||||
/* { dg-do run { xfail mips*-*-* arm*-*-* strongarm*-*-* xscale*-*-* } } */
|
||||
/* { dg-do run { xfail mips*-*-* arm*-*-* strongarm*-*-* xscale*-*-* } } */
|
||||
#include "ffitest.h"
|
||||
|
||||
typedef struct struct_72byte {
|
||||
@@ -39,7 +39,7 @@ struct_72byte cls_struct_72byte_fn(
|
||||
result.h = b0.h + b1.h + b2.h + b3.h;
|
||||
result.i = b0.i + b1.i + b2.i + b3.i;
|
||||
|
||||
printf("%g %g %g %g %g %g %g %g %" PRId64 "\n", result.a, result.b, result.c,
|
||||
printf("%g %g %g %g %g %g %g %g %" PRIdLL "\n", result.a, result.b, result.c,
|
||||
result.d, result.e, result.f, result.g, result.h, result.i);
|
||||
|
||||
return result;
|
||||
@@ -107,7 +107,7 @@ int main (void)
|
||||
|
||||
ffi_call(&cif, FFI_FN(cls_struct_72byte_fn), &res_dbl, args_dbl);
|
||||
/* { dg-output "22 15 17 25 6 13 19 18 16" } */
|
||||
printf("res: %g %g %g %g %g %g %g %g %" PRId64 "\n", res_dbl.a, res_dbl.b, res_dbl.c,
|
||||
printf("res: %g %g %g %g %g %g %g %g %" PRIdLL "\n", res_dbl.a, res_dbl.b, res_dbl.c,
|
||||
res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g, res_dbl.h, res_dbl.i);
|
||||
/* { dg-output "\nres: 22 15 17 25 6 13 19 18 16" } */
|
||||
|
||||
@@ -116,7 +116,7 @@ int main (void)
|
||||
res_dbl = ((struct_72byte(*)(struct_72byte, struct_72byte,
|
||||
struct_72byte, struct_72byte))(code))(e_dbl, f_dbl, g_dbl, h_dbl);
|
||||
/* { dg-output "\n22 15 17 25 6 13 19 18 16" } */
|
||||
printf("res: %g %g %g %g %g %g %g %g %" PRId64 "\n", res_dbl.a, res_dbl.b, res_dbl.c,
|
||||
printf("res: %g %g %g %g %g %g %g %g %" PRIdLL "\n", res_dbl.a, res_dbl.b, res_dbl.c,
|
||||
res_dbl.d, res_dbl.e, res_dbl.f, res_dbl.g, res_dbl.h, res_dbl.i);
|
||||
/* { dg-output "\nres: 22 15 17 25 6 13 19 18 16" } */
|
||||
|
||||
|
||||
@@ -43,6 +43,16 @@
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* MinGW kludge. */
|
||||
#ifdef WIN64
|
||||
#define PRIdLL "PRId64"
|
||||
#define PRIuLL "PRIu64"
|
||||
#else
|
||||
#define PRIdLL "lld"
|
||||
#define PRIuLL "llu"
|
||||
#endif
|
||||
|
||||
#ifdef USING_MMAP
|
||||
static inline void *
|
||||
allocate_mmap (size_t size)
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
/* { dg-do run } */
|
||||
#include "ffitestcxx.h"
|
||||
#include <stdint.h>
|
||||
|
||||
void
|
||||
closure_test_fn(ffi_cif* cif __UNUSED__, void* resp __UNUSED__,
|
||||
|
||||
@@ -77,11 +77,7 @@ _exc_handler(struct _EXCEPTION_RECORD* exception_record,
|
||||
#define PROTECTED_END(ONERR) } __except((PROTECT)?EXCEPTION_EXECUTE_HANDLER:EXCEPTION_CONTINUE_SEARCH) { ONERR; }
|
||||
#else
|
||||
#ifdef _WIN64
|
||||
// FIXME: mingw64 is untested
|
||||
#define SEH_TRY(ER) \
|
||||
__asm__ ("pushq %0;pushq %%gs:0;movq %%rsp,%%gs:0;" : : "g" (&(ER)))
|
||||
#define SEH_CATCH(ER) \
|
||||
__asm__ ("movq (%%rsp),%%rax;movq %%rax,%%gs:0;addq $16,%%rsp" : : : "%rax")
|
||||
#error "GCC does not implement SEh"
|
||||
#else
|
||||
#define SEH_TRY(ER) \
|
||||
__asm__ ("movl %%fs:0, %0" : "=r" ((ER).ex_reg.prev)); \
|
||||
@@ -115,11 +111,14 @@ _exc_handler(struct _EXCEPTION_RECORD* exception_record,
|
||||
#endif /* !_MSC_VER */
|
||||
|
||||
#else // _WIN32
|
||||
|
||||
// Most other platforms support signals
|
||||
// Catch both SIGSEGV and SIGBUS
|
||||
#include <signal.h>
|
||||
#include <setjmp.h>
|
||||
static jmp_buf _context;
|
||||
static void* _old_segv_handler = NULL;
|
||||
static void* _old_bus_handler = NULL;
|
||||
static volatile int _error;
|
||||
static void _exc_handler(int sig) {
|
||||
if (sig == SIGSEGV || sig == SIGBUS) {
|
||||
@@ -128,9 +127,6 @@ static void _exc_handler(int sig) {
|
||||
}
|
||||
|
||||
#define PROTECTED_START() \
|
||||
void* _old_segv_handler; \
|
||||
void* _old_bus_handler; \
|
||||
int _error = 0; \
|
||||
if (PROTECT) { \
|
||||
_old_segv_handler = signal(SIGSEGV, _exc_handler); \
|
||||
_old_bus_handler = signal(SIGBUS, _exc_handler); \
|
||||
|
||||
@@ -19,6 +19,7 @@ extern "C" {
|
||||
#include <wchar.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
typedef signed char int8_t;
|
||||
@@ -30,6 +31,11 @@ typedef __int64 int64_t;
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef UNICODE
|
||||
#define UNICODE
|
||||
#endif
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#define EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define EXPORT
|
||||
@@ -66,6 +72,15 @@ struct CheckFieldAlignment {
|
||||
|
||||
static int _callCount;
|
||||
|
||||
EXPORT void
|
||||
setLastError(int err) {
|
||||
#ifdef _WIN32
|
||||
SetLastError(err);
|
||||
#else
|
||||
errno = err;
|
||||
#endif
|
||||
}
|
||||
|
||||
EXPORT int
|
||||
callCount() {
|
||||
return ++_callCount;
|
||||
@@ -331,6 +346,11 @@ incrementInt32ByReference(int32_t *arg) {
|
||||
if (arg) ++*arg;
|
||||
}
|
||||
|
||||
EXPORT void
|
||||
incrementNativeLongByReference(long *arg) {
|
||||
if (arg) ++*arg;
|
||||
}
|
||||
|
||||
EXPORT void
|
||||
incrementInt64ByReference(int64_t *arg) {
|
||||
if (arg) ++*arg;
|
||||
@@ -553,6 +573,28 @@ callInt32Callback(int32_t (*func)(int32_t arg, int32_t arg2),
|
||||
return (*func)(arg, arg2);
|
||||
}
|
||||
|
||||
EXPORT int32_t
|
||||
callInt32CallbackRepeatedly(int32_t (*func)(int32_t arg, int32_t arg2),
|
||||
int32_t arg, int32_t arg2, int32_t count) {
|
||||
int i;
|
||||
int sum = 0;
|
||||
for (i=0;i < count;i++) {
|
||||
sum += (*func)(arg, arg2);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
EXPORT long
|
||||
callLongCallbackRepeatedly(long (*func)(long arg, long arg2),
|
||||
long arg, long arg2, int32_t count) {
|
||||
int i;
|
||||
long sum = 0;
|
||||
for (i=0;i < count;i++) {
|
||||
sum += (*func)(arg, arg2);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
EXPORT long
|
||||
callNativeLongCallback(long (*func)(long arg, long arg2),
|
||||
long arg, long arg2) {
|
||||
@@ -768,7 +810,7 @@ callInt32StdCallCallback(int32_t (__stdcall *func)(int32_t arg, int32_t arg2),
|
||||
#include <jni.h>
|
||||
#include <math.h>
|
||||
JNIEXPORT jdouble JNICALL
|
||||
Java_com_sun_jna_RawTest_00024JNI_cos(JNIEnv *env, jclass cls, jdouble x) {
|
||||
Java_com_sun_jna_DirectTest_00024JNI_cos(JNIEnv *env, jclass cls, jdouble x) {
|
||||
return cos(x);
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -6,7 +6,7 @@
|
||||
<groupId>net.java.dev.jna</groupId>
|
||||
<artifactId>jna</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>3.1.0</version>
|
||||
<version>3.2.1</version>
|
||||
<name>Java Native Access</name>
|
||||
|
||||
<distributionManagement>
|
||||
@@ -33,6 +33,7 @@
|
||||
<tasks>
|
||||
<!--<ant dir="." target="dist" />-->
|
||||
<attachArtifact file="dist/jna.jar" />
|
||||
<attachArtifact file="dist/examples.jar" />
|
||||
<attachArtifact file="dist/src-mvn.zip" classifier="sources" type="jar"/>
|
||||
</tasks>
|
||||
</configuration>
|
||||
|
||||
@@ -1,10 +1,46 @@
|
||||
<a name="top"></a>
|
||||
<h2>Release 3.2.1</h2>
|
||||
<b>Features</b><br>
|
||||
<ul>
|
||||
<li>Add HRESULT, LONG mapping to W32API (marc strapetz).
|
||||
</ul>
|
||||
<b>Bug Fixes</b><br>
|
||||
<ul>
|
||||
<li>Fix definition of HWND_BROADCAST in W32API.
|
||||
<li>Fix memory alignment checking (<a href="https://jna.dev.java.net/issues/show_bug.cgi?id=121">Issue 121</a>).
|
||||
<li>Fix
|
||||
Structure <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Object.html#equals(java.lang.Object)">equals/hashCode</a>
|
||||
implementation, based on current Java fields rather than strictly native
|
||||
memory contents. Avoid using equals/hashCode when avoiding recursive
|
||||
reads/writes.
|
||||
</ul>
|
||||
<h2>Release 3.2.0</h2>
|
||||
<b>Features</b><br>
|
||||
<ul>
|
||||
<li>Handle String, Structure, Callback, Buffer, and primitive arrays in direct
|
||||
mappings. Handle NativeMapped and TypeMapper, with optimized paths for
|
||||
IntegerType and PointerType.
|
||||
<li>Optionally throw errno/GetLastError as an exception. This is preferred to
|
||||
(and more efficient than) calling Native.getLastError().
|
||||
<li>Unload/delete native library unpacked from jna.jar if Native class is garbage collected. Only install shutdown hook if using the system class loader.
|
||||
<li>Auto-write contiguous Structure arrays when first element is written.
|
||||
<li>Support NativeMapped[] as function arguments for interface-mapped
|
||||
libraries (<a href="https://jna.dev.java.net/issues/show_bug.cgi?id=90">Issue 90</a>).
|
||||
<li>Enable function lookup within current process on Windows.
|
||||
</ul>
|
||||
<b>Bug Fixes</b><br>
|
||||
<ul>
|
||||
<li>Restrict recursive structure reads/writes by thread instead of globally.
|
||||
This avoids potentially missed reads/writes with concurrent access (<a href="https://jna.dev.java.net/issues/show_bug.cgi?id=120">Issue 120</a>).
|
||||
<li>Ensure Memory is not GC'd and freed if direct NIO buffers mapped to it are extant.
|
||||
<li>Allow types derived from java.nio.Buffer as Structure fields.
|
||||
</ul>
|
||||
<h2>Release 3.1.0</h2>
|
||||
<b>Features</b><br>
|
||||
<ul>
|
||||
<li>Add raw JNI mapping of static Java methods. Performance is about 10X that of traditional JNA interface mapping, although with less type conversion functionality.
|
||||
<li>Add library option to allow passing/return of Java Objects.
|
||||
<li>Allow handling of uncaught callback exceptions (<a href="https://jna.dev.java.net/issues/show_bug.cgi?id=63">Issue 63)</a>.
|
||||
<li>Allow handling of uncaught callback exceptions (<a href="https://jna.dev.java.net/issues/show_bug.cgi?id=63">Issue 63</a>).
|
||||
<li>Object oriented interface to X server (see contrib/x11)
|
||||
<li>Make Memory class more accessible.
|
||||
<li>Provide Structure ctor with Pointer argument (<a href="https://jna.dev.java.net/issues/show_bug.cgi?id=102">issue 102</a>).
|
||||
|
||||
@@ -32,7 +32,7 @@ import java.util.WeakHashMap;
|
||||
class CallbackReference extends WeakReference {
|
||||
|
||||
static final Map callbackMap = new WeakHashMap();
|
||||
static final Map altCallbackMap = new WeakHashMap();
|
||||
static final Map directCallbackMap = new WeakHashMap();
|
||||
static final Map allocations = new WeakHashMap();
|
||||
private static final Method PROXY_CALLBACK_METHOD;
|
||||
|
||||
@@ -51,83 +51,133 @@ class CallbackReference extends WeakReference {
|
||||
* Java Callback. Otherwise, return a proxy to the native function pointer.
|
||||
*/
|
||||
public static Callback getCallback(Class type, Pointer p) {
|
||||
if (p != null) {
|
||||
if (!type.isInterface())
|
||||
throw new IllegalArgumentException("Callback type must be an interface");
|
||||
Map map = AltCallingConvention.class.isAssignableFrom(type)
|
||||
? altCallbackMap : callbackMap;
|
||||
synchronized(map) {
|
||||
for (Iterator i=map.keySet().iterator();i.hasNext();) {
|
||||
Callback cb = (Callback)i.next();
|
||||
if (type.isAssignableFrom(cb.getClass())) {
|
||||
CallbackReference cbref = (CallbackReference)map.get(cb);
|
||||
Pointer cbp = cbref != null
|
||||
? cbref.getTrampoline() : getNativeFunctionPointer(cb);
|
||||
if (p.equals(cbp)) {
|
||||
return cb;
|
||||
}
|
||||
return getCallback(type, p, false);
|
||||
}
|
||||
|
||||
private static Callback getCallback(Class type, Pointer p, boolean direct) {
|
||||
if (p == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!type.isInterface())
|
||||
throw new IllegalArgumentException("Callback type must be an interface");
|
||||
Map map = direct ? directCallbackMap : callbackMap;
|
||||
synchronized(map) {
|
||||
for (Iterator i=map.keySet().iterator();i.hasNext();) {
|
||||
Callback cb = (Callback)i.next();
|
||||
if (type.isAssignableFrom(cb.getClass())) {
|
||||
CallbackReference cbref = (CallbackReference)map.get(cb);
|
||||
Pointer cbp = cbref != null
|
||||
? cbref.getTrampoline() : getNativeFunctionPointer(cb);
|
||||
if (p.equals(cbp)) {
|
||||
return cb;
|
||||
}
|
||||
}
|
||||
int ctype = AltCallingConvention.class.isAssignableFrom(type)
|
||||
? Function.ALT_CONVENTION : Function.C_CONVENTION;
|
||||
Map options = Native.getLibraryOptions(type);
|
||||
NativeFunctionHandler h = new NativeFunctionHandler(p, ctype, options);
|
||||
Callback cb = (Callback)Proxy.newProxyInstance(type.getClassLoader(), new Class[] { type }, h);
|
||||
h.options.put(Function.OPTION_INVOKING_METHOD, getCallbackMethod(cb));
|
||||
map.put(cb, null);
|
||||
return cb;
|
||||
}
|
||||
int ctype = AltCallingConvention.class.isAssignableFrom(type)
|
||||
? Function.ALT_CONVENTION : Function.C_CONVENTION;
|
||||
Map foptions = new HashMap();
|
||||
Map options = Native.getLibraryOptions(type);
|
||||
if (options != null) {
|
||||
foptions.putAll(options);
|
||||
}
|
||||
foptions.put(Function.OPTION_INVOKING_METHOD, getCallbackMethod(type));
|
||||
NativeFunctionHandler h = new NativeFunctionHandler(p, ctype, foptions);
|
||||
Callback cb = (Callback)Proxy.newProxyInstance(type.getClassLoader(), new Class[] { type }, h);
|
||||
map.put(cb, null);
|
||||
return cb;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Pointer cbstruct;
|
||||
// Keep a reference to avoid premature GC
|
||||
// Keep a reference to the proxy to avoid premature GC of it
|
||||
CallbackProxy proxy;
|
||||
private CallbackReference(Callback callback, int callingConvention) {
|
||||
Method method;
|
||||
private CallbackReference(Callback callback, int callingConvention, boolean direct) {
|
||||
super(callback);
|
||||
TypeMapper mapper = Native.getTypeMapper(Native.findCallbackClass(callback.getClass()));
|
||||
if (callback instanceof CallbackProxy) {
|
||||
proxy = (CallbackProxy)callback;
|
||||
}
|
||||
else {
|
||||
proxy = new DefaultCallbackProxy(getCallbackMethod(callback), mapper);
|
||||
}
|
||||
TypeMapper mapper = Native.getTypeMapper(callback.getClass());
|
||||
Class[] nativeParamTypes;
|
||||
Class returnType;
|
||||
|
||||
// Generate a list of parameter types that the native code can
|
||||
// handle. Let the CallbackProxy do any further conversion
|
||||
// to match the true Java callback method signature
|
||||
Class[] nativeParamTypes = proxy.getParameterTypes();
|
||||
Class returnType = proxy.getReturnType();
|
||||
if (mapper != null) {
|
||||
for (int i=0;i < nativeParamTypes.length;i++) {
|
||||
FromNativeConverter rc = mapper.getFromNativeConverter(nativeParamTypes[i]);
|
||||
if (rc != null) {
|
||||
nativeParamTypes[i] = rc.nativeType();
|
||||
// Check whether direct mapping may be used, or whether
|
||||
// we need to fall back to conventional mapping
|
||||
String arch = System.getProperty("os.arch").toLowerCase();
|
||||
boolean ppc = "ppc".equals(arch) || "powerpc".equals(arch);
|
||||
if (direct) {
|
||||
Method m = getCallbackMethod(callback);
|
||||
Class[] ptypes = m.getParameterTypes();
|
||||
for (int i=0;i < ptypes.length;i++) {
|
||||
// varargs w/FP args via ffi_call fails on ppc (darwin)
|
||||
if (ppc && (ptypes[i] == float.class
|
||||
|| ptypes[i] == double.class)) {
|
||||
direct = false;
|
||||
break;
|
||||
}
|
||||
// No TypeMapper support in native callback code
|
||||
if (mapper != null
|
||||
&& mapper.getFromNativeConverter(ptypes[i]) != null) {
|
||||
direct = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ToNativeConverter tn = mapper.getToNativeConverter(returnType);
|
||||
if (tn != null) {
|
||||
returnType = tn.nativeType();
|
||||
if (mapper != null
|
||||
&& mapper.getToNativeConverter(m.getReturnType()) != null) {
|
||||
direct = false;
|
||||
}
|
||||
}
|
||||
for (int i=0;i < nativeParamTypes.length;i++) {
|
||||
nativeParamTypes[i] = getNativeType(nativeParamTypes[i]);
|
||||
if (!isAllowableNativeType(nativeParamTypes[i])) {
|
||||
String msg = "Callback argument " + nativeParamTypes[i]
|
||||
|
||||
if (direct) {
|
||||
method = getCallbackMethod(callback);
|
||||
nativeParamTypes = method.getParameterTypes();
|
||||
returnType = method.getReturnType();
|
||||
cbstruct = createNativeCallback(callback, method,
|
||||
nativeParamTypes, returnType,
|
||||
callingConvention, true);
|
||||
}
|
||||
else {
|
||||
if (callback instanceof CallbackProxy) {
|
||||
proxy = (CallbackProxy)callback;
|
||||
}
|
||||
else {
|
||||
proxy = new DefaultCallbackProxy(getCallbackMethod(callback), mapper);
|
||||
}
|
||||
nativeParamTypes = proxy.getParameterTypes();
|
||||
returnType = proxy.getReturnType();
|
||||
|
||||
// Generate a list of parameter types that the native code can
|
||||
// handle. Let the CallbackProxy do any further conversion
|
||||
// to match the true Java callback method signature
|
||||
if (mapper != null) {
|
||||
for (int i=0;i < nativeParamTypes.length;i++) {
|
||||
FromNativeConverter rc = mapper.getFromNativeConverter(nativeParamTypes[i]);
|
||||
if (rc != null) {
|
||||
nativeParamTypes[i] = rc.nativeType();
|
||||
}
|
||||
}
|
||||
ToNativeConverter tn = mapper.getToNativeConverter(returnType);
|
||||
if (tn != null) {
|
||||
returnType = tn.nativeType();
|
||||
}
|
||||
}
|
||||
for (int i=0;i < nativeParamTypes.length;i++) {
|
||||
nativeParamTypes[i] = getNativeType(nativeParamTypes[i]);
|
||||
if (!isAllowableNativeType(nativeParamTypes[i])) {
|
||||
String msg = "Callback argument " + nativeParamTypes[i]
|
||||
+ " requires custom type conversion";
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
}
|
||||
returnType = getNativeType(returnType);
|
||||
if (!isAllowableNativeType(returnType)) {
|
||||
String msg = "Callback return type " + returnType
|
||||
+ " requires custom type conversion";
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
cbstruct = createNativeCallback(proxy, PROXY_CALLBACK_METHOD,
|
||||
nativeParamTypes, returnType,
|
||||
callingConvention, false);
|
||||
}
|
||||
returnType = getNativeType(returnType);
|
||||
if (!isAllowableNativeType(returnType)) {
|
||||
String msg = "Callback return type " + returnType
|
||||
+ " requires custom type conversion";
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
cbstruct = createNativeCallback(proxy, PROXY_CALLBACK_METHOD,
|
||||
nativeParamTypes, returnType,
|
||||
callingConvention);
|
||||
|
||||
}
|
||||
|
||||
private Class getNativeType(Class cls) {
|
||||
@@ -154,14 +204,47 @@ class CallbackReference extends WeakReference {
|
||||
if (m.getParameterTypes().length > Function.MAX_NARGS) {
|
||||
String msg = "Method signature exceeds the maximum "
|
||||
+ "parameter count: " + m;
|
||||
throw new IllegalArgumentException(msg);
|
||||
throw new UnsupportedOperationException(msg);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
/** Find the first instance of an interface which implements the Callback
|
||||
* interface or an interface derived from Callback, which defines an
|
||||
* appropriate callback method.
|
||||
*/
|
||||
static Class findCallbackClass(Class type) {
|
||||
if (!Callback.class.isAssignableFrom(type)) {
|
||||
throw new IllegalArgumentException(type.getName() + " is not derived from com.sun.jna.Callback");
|
||||
}
|
||||
if (type.isInterface()) {
|
||||
return type;
|
||||
}
|
||||
Class[] ifaces = type.getInterfaces();
|
||||
for (int i=0;i < ifaces.length;i++) {
|
||||
if (Callback.class.isAssignableFrom(ifaces[i])) {
|
||||
try {
|
||||
// Make sure it's got a recognizable callback method
|
||||
getCallbackMethod(ifaces[i]);
|
||||
return ifaces[i];
|
||||
}
|
||||
catch(IllegalArgumentException e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Callback.class.isAssignableFrom(type.getSuperclass())) {
|
||||
return findCallbackClass(type.getSuperclass());
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
private static Method getCallbackMethod(Callback callback) {
|
||||
return getCallbackMethod(findCallbackClass(callback.getClass()));
|
||||
}
|
||||
|
||||
private static Method getCallbackMethod(Class cls) {
|
||||
// Look at only public methods defined by the Callback class
|
||||
Class cls = Native.findCallbackClass(callback.getClass());
|
||||
Method[] pubMethods = cls.getDeclaredMethods();
|
||||
Method[] classMethods = cls.getMethods();
|
||||
Set pmethods = new HashSet(Arrays.asList(pubMethods));
|
||||
@@ -218,19 +301,25 @@ class CallbackReference extends WeakReference {
|
||||
* given callback.
|
||||
*/
|
||||
public static Pointer getFunctionPointer(Callback cb) {
|
||||
return getFunctionPointer(cb, false);
|
||||
}
|
||||
|
||||
/** Native code calls this with direct=true. */
|
||||
private static Pointer getFunctionPointer(Callback cb, boolean direct) {
|
||||
Pointer fp = null;
|
||||
if (cb == null) return null;
|
||||
if (cb == null) {
|
||||
return null;
|
||||
}
|
||||
if ((fp = getNativeFunctionPointer(cb)) != null) {
|
||||
return fp;
|
||||
}
|
||||
int callingConvention = cb instanceof AltCallingConvention
|
||||
? Function.ALT_CONVENTION : Function.C_CONVENTION;
|
||||
Map map = callingConvention == Function.ALT_CONVENTION
|
||||
? altCallbackMap : callbackMap;
|
||||
Map map = direct ? directCallbackMap : callbackMap;
|
||||
synchronized(map) {
|
||||
CallbackReference cbref = (CallbackReference)map.get(cb);
|
||||
if (cbref == null) {
|
||||
cbref = new CallbackReference(cb, callingConvention);
|
||||
cbref = new CallbackReference(cb, callingConvention, direct);
|
||||
map.put(cb, cbref);
|
||||
}
|
||||
return cbref.getTrampoline();
|
||||
@@ -281,9 +370,11 @@ class CallbackReference extends WeakReference {
|
||||
if (fromNative[i] != null) {
|
||||
FromNativeContext context =
|
||||
new CallbackParameterContext(type, callbackMethod, args, i);
|
||||
arg = fromNative[i].fromNative(arg, context);
|
||||
callbackArgs[i] = fromNative[i].fromNative(arg, context);
|
||||
}
|
||||
else {
|
||||
callbackArgs[i] = convertArgument(arg, type);
|
||||
}
|
||||
callbackArgs[i] = convertArgument(arg, type);
|
||||
}
|
||||
|
||||
Object result = null;
|
||||
@@ -379,10 +470,7 @@ class CallbackReference extends WeakReference {
|
||||
Function.INTEGER_TRUE : Function.INTEGER_FALSE;
|
||||
}
|
||||
else if (cls == String.class || cls == WString.class) {
|
||||
NativeString ns = new NativeString(value.toString(), cls == WString.class);
|
||||
// Delay GC until string itself is GC'd.
|
||||
allocations.put(value, ns);
|
||||
return ns.getPointer();
|
||||
return getNativeString(value, cls == WString.class);
|
||||
}
|
||||
else if (cls == String[].class || cls == WString.class) {
|
||||
StringArray sa = cls == String[].class
|
||||
@@ -413,28 +501,20 @@ class CallbackReference extends WeakReference {
|
||||
private Function function;
|
||||
private Map options;
|
||||
|
||||
public NativeFunctionHandler(Pointer address, int callingConvention, Map libOptions) {
|
||||
this.function = new Function(address, callingConvention) {
|
||||
public String getName() {
|
||||
String str = super.getName();
|
||||
if (options.containsKey(Function.OPTION_INVOKING_METHOD)) {
|
||||
Method m = (Method)options.get(Function.OPTION_INVOKING_METHOD);
|
||||
Class cls = Native.findCallbackClass(m.getDeclaringClass());
|
||||
str += " (" + cls.getName() + ")";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
};
|
||||
this.options = new HashMap();
|
||||
if (libOptions != null) {
|
||||
options.putAll(libOptions);
|
||||
}
|
||||
public NativeFunctionHandler(Pointer address, int callingConvention, Map options) {
|
||||
this.function = new Function(address, callingConvention);
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
/** Chain invocation to the native function. */
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
if (Library.Handler.OBJECT_TOSTRING.equals(method)) {
|
||||
return "Proxy interface to " + function;
|
||||
String str = "Proxy interface to " + function;
|
||||
Method m = (Method)options.get(Function.OPTION_INVOKING_METHOD);
|
||||
Class cls = findCallbackClass(m.getDeclaringClass());
|
||||
str += " (" + cls.getName() + ")";
|
||||
|
||||
return str;
|
||||
}
|
||||
else if (Library.Handler.OBJECT_HASHCODE.equals(method)) {
|
||||
return new Integer(hashCode());
|
||||
@@ -475,13 +555,23 @@ class CallbackReference extends WeakReference {
|
||||
|| Pointer.class.isAssignableFrom(cls);
|
||||
}
|
||||
|
||||
private static Pointer getNativeString(Object value, boolean wide) {
|
||||
if (value != null) {
|
||||
NativeString ns = new NativeString(value.toString(), wide);
|
||||
// Delay GC until string itself is GC'd.
|
||||
allocations.put(value, ns);
|
||||
return ns.getPointer();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Create a native trampoline to delegate execution to the Java callback.
|
||||
*/
|
||||
private static synchronized native Pointer createNativeCallback(CallbackProxy callback,
|
||||
private static synchronized native Pointer createNativeCallback(Callback callback,
|
||||
Method method,
|
||||
Class[] parameterTypes,
|
||||
Class returnType,
|
||||
int callingConvention);
|
||||
int callingConvention, boolean direct);
|
||||
/** Free the given callback trampoline. */
|
||||
private static synchronized native void freeNativeCallback(long ptr);
|
||||
}
|
||||
|
||||
@@ -45,6 +45,10 @@ public class Function extends Pointer {
|
||||
/** First alternate convention (currently used only for w32 stdcall). */
|
||||
public static final int ALT_CONVENTION = 1;
|
||||
|
||||
private static final int MASK_CC = 0x3;
|
||||
/** Whether to throw an exception if last error is non-zero after call. */
|
||||
public static final int THROW_LAST_ERROR = (1<<2);
|
||||
|
||||
static final Integer INTEGER_TRUE = new Integer(-1);
|
||||
static final Integer INTEGER_FALSE = new Integer(0);
|
||||
|
||||
@@ -79,20 +83,21 @@ public class Function extends Pointer {
|
||||
* Library in which to find the function
|
||||
* @param functionName
|
||||
* Name of the native function to be linked with
|
||||
* @param callConvention
|
||||
* @param callFlags
|
||||
* Call convention used by the native function
|
||||
* @throws {@link UnsatisfiedLinkError} if the library is not found or
|
||||
* the given function name is not found within the library.
|
||||
*/
|
||||
public static Function getFunction(String libraryName, String functionName, int callConvention) {
|
||||
return NativeLibrary.getInstance(libraryName).getFunction(functionName, callConvention);
|
||||
public static Function getFunction(String libraryName, String functionName, int callFlags) {
|
||||
return NativeLibrary.getInstance(libraryName).getFunction(functionName, callFlags);
|
||||
}
|
||||
|
||||
// Keep a reference to the NativeLibrary so it does not get garbage collected
|
||||
// until the function is
|
||||
private NativeLibrary library;
|
||||
private final String functionName;
|
||||
final int callingConvention;
|
||||
int callFlags;
|
||||
final Map options;
|
||||
|
||||
/** For internal JNA use. */
|
||||
static final String OPTION_INVOKING_METHOD = "invoking-method";
|
||||
@@ -109,18 +114,19 @@ public class Function extends Pointer {
|
||||
* {@link NativeLibrary} in which to find the function
|
||||
* @param functionName
|
||||
* Name of the native function to be linked with
|
||||
* @param callingConvention
|
||||
* @param callFlags
|
||||
* Calling convention used by the native function
|
||||
* @throws {@link UnsatisfiedLinkError} if the given function name is
|
||||
* not found within the library.
|
||||
*/
|
||||
Function(NativeLibrary library, String functionName, int callingConvention) {
|
||||
checkCallingConvention(callingConvention);
|
||||
Function(NativeLibrary library, String functionName, int callFlags) {
|
||||
checkCallingConvention(callFlags & MASK_CC);
|
||||
if (functionName == null)
|
||||
throw new NullPointerException("Function name must not be null");
|
||||
this.library = library;
|
||||
this.functionName = functionName;
|
||||
this.callingConvention = callingConvention;
|
||||
this.callFlags = callFlags;
|
||||
this.options = library.options;
|
||||
try {
|
||||
this.peer = library.getSymbolAddress(functionName);
|
||||
}
|
||||
@@ -141,18 +147,19 @@ public class Function extends Pointer {
|
||||
*
|
||||
* @param functionAddress
|
||||
* Address of the native function
|
||||
* @param callingConvention
|
||||
* @param callFlags
|
||||
* Calling convention used by the native function
|
||||
*/
|
||||
Function(Pointer functionAddress, int callingConvention) {
|
||||
checkCallingConvention(callingConvention);
|
||||
Function(Pointer functionAddress, int callFlags) {
|
||||
checkCallingConvention(callFlags & MASK_CC);
|
||||
if (functionAddress == null
|
||||
|| functionAddress.peer == 0) {
|
||||
throw new NullPointerException("Function address may not be null");
|
||||
}
|
||||
this.functionName = functionAddress.toString();
|
||||
this.callingConvention = callingConvention;
|
||||
this.callFlags = callFlags;
|
||||
this.peer = functionAddress.peer;
|
||||
this.options = Collections.EMPTY_MAP;
|
||||
}
|
||||
|
||||
private void checkCallingConvention(int convention)
|
||||
@@ -173,14 +180,14 @@ public class Function extends Pointer {
|
||||
|
||||
|
||||
public int getCallingConvention() {
|
||||
return callingConvention;
|
||||
return callFlags & MASK_CC;
|
||||
}
|
||||
|
||||
/** Invoke the native function with the given arguments, returning the
|
||||
* native result as an Object.
|
||||
*/
|
||||
public Object invoke(Class returnType, Object[] inArgs) {
|
||||
return invoke(returnType, inArgs, Collections.EMPTY_MAP);
|
||||
return invoke(returnType, inArgs, this.options);
|
||||
}
|
||||
|
||||
/** Invoke the native function with the given arguments, returning the
|
||||
@@ -243,9 +250,7 @@ public class Function extends Pointer {
|
||||
continue;
|
||||
if (inArg instanceof Structure) {
|
||||
if (!(inArg instanceof Structure.ByValue)) {
|
||||
if (((Structure)inArg).getAutoRead()) {
|
||||
((Structure)inArg).read();
|
||||
}
|
||||
((Structure)inArg).autoRead();
|
||||
}
|
||||
}
|
||||
else if (args[i] instanceof PostCallRead) {
|
||||
@@ -265,9 +270,7 @@ public class Function extends Pointer {
|
||||
else if (Structure[].class.isAssignableFrom(inArg.getClass())) {
|
||||
Structure[] ss = (Structure[])inArg;
|
||||
for (int si=0;si < ss.length;si++) {
|
||||
if (ss[si].getAutoRead()) {
|
||||
ss[si].read();
|
||||
}
|
||||
ss[si].autoRead();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -280,81 +283,77 @@ public class Function extends Pointer {
|
||||
Object invoke(Object[] args, Class returnType, boolean allowObjects) {
|
||||
Object result = null;
|
||||
if (returnType == null || returnType==void.class || returnType==Void.class) {
|
||||
invokeVoid(callingConvention, args);
|
||||
invokeVoid(callFlags, args);
|
||||
result = null;
|
||||
}
|
||||
else if (returnType==boolean.class || returnType==Boolean.class) {
|
||||
result = valueOf(invokeInt(callingConvention, args) != 0);
|
||||
result = valueOf(invokeInt(callFlags, args) != 0);
|
||||
}
|
||||
else if (returnType==byte.class || returnType==Byte.class) {
|
||||
result = new Byte((byte)invokeInt(callingConvention, args));
|
||||
result = new Byte((byte)invokeInt(callFlags, args));
|
||||
}
|
||||
else if (returnType==short.class || returnType==Short.class) {
|
||||
result = new Short((short)invokeInt(callingConvention, args));
|
||||
result = new Short((short)invokeInt(callFlags, args));
|
||||
}
|
||||
else if (returnType==char.class || returnType==Character.class) {
|
||||
result = new Character((char)invokeInt(callingConvention, args));
|
||||
result = new Character((char)invokeInt(callFlags, args));
|
||||
}
|
||||
else if (returnType==int.class || returnType==Integer.class) {
|
||||
result = new Integer(invokeInt(callingConvention, args));
|
||||
result = new Integer(invokeInt(callFlags, args));
|
||||
}
|
||||
else if (returnType==long.class || returnType==Long.class) {
|
||||
result = new Long(invokeLong(callingConvention, args));
|
||||
result = new Long(invokeLong(callFlags, args));
|
||||
}
|
||||
else if (returnType==float.class || returnType==Float.class) {
|
||||
result = new Float(invokeFloat(callingConvention, args));
|
||||
result = new Float(invokeFloat(callFlags, args));
|
||||
}
|
||||
else if (returnType==double.class || returnType==Double.class) {
|
||||
result = new Double(invokeDouble(callingConvention, args));
|
||||
result = new Double(invokeDouble(callFlags, args));
|
||||
}
|
||||
else if (returnType==String.class) {
|
||||
result = invokeString(callingConvention, args, false);
|
||||
result = invokeString(callFlags, args, false);
|
||||
}
|
||||
else if (returnType==WString.class) {
|
||||
String s = invokeString(callingConvention, args, true);
|
||||
String s = invokeString(callFlags, args, true);
|
||||
if (s != null) {
|
||||
result = new WString(s);
|
||||
}
|
||||
}
|
||||
else if (Pointer.class.isAssignableFrom(returnType)) {
|
||||
result = invokePointer(callingConvention, args);
|
||||
result = invokePointer(callFlags, args);
|
||||
}
|
||||
else if (Structure.class.isAssignableFrom(returnType)) {
|
||||
if (Structure.ByValue.class.isAssignableFrom(returnType)) {
|
||||
Structure s =
|
||||
invokeStructure(callingConvention, args,
|
||||
invokeStructure(callFlags, args,
|
||||
Structure.newInstance(returnType));
|
||||
if (s.getAutoRead()) {
|
||||
s.read();
|
||||
}
|
||||
s.autoRead();
|
||||
result = s;
|
||||
}
|
||||
else {
|
||||
result = invokePointer(callingConvention, args);
|
||||
result = invokePointer(callFlags, args);
|
||||
if (result != null) {
|
||||
Structure s = Structure.newInstance(returnType);
|
||||
s.useMemory((Pointer)result);
|
||||
if (s.getAutoRead()) {
|
||||
s.read();
|
||||
}
|
||||
s.autoRead();
|
||||
result = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Callback.class.isAssignableFrom(returnType)) {
|
||||
result = invokePointer(callingConvention, args);
|
||||
result = invokePointer(callFlags, args);
|
||||
if (result != null) {
|
||||
result = CallbackReference.getCallback(returnType, (Pointer)result);
|
||||
}
|
||||
}
|
||||
else if (returnType==String[].class) {
|
||||
Pointer p = invokePointer(callingConvention, args);
|
||||
Pointer p = invokePointer(callFlags, args);
|
||||
if (p != null) {
|
||||
result = p.getStringArray(0);
|
||||
}
|
||||
}
|
||||
else if (returnType==WString[].class) {
|
||||
Pointer p = invokePointer(callingConvention, args);
|
||||
Pointer p = invokePointer(callFlags, args);
|
||||
if (p != null) {
|
||||
String[] arr = p.getStringArray(0, true);
|
||||
WString[] warr = new WString[arr.length];
|
||||
@@ -365,18 +364,18 @@ public class Function extends Pointer {
|
||||
}
|
||||
}
|
||||
else if (returnType==Pointer[].class) {
|
||||
Pointer p = invokePointer(callingConvention, args);
|
||||
Pointer p = invokePointer(callFlags, args);
|
||||
if (p != null) {
|
||||
result = p.getPointerArray(0);
|
||||
}
|
||||
}
|
||||
else if (allowObjects) {
|
||||
result = invokeObject(callingConvention, args);
|
||||
result = invokeObject(callFlags, args);
|
||||
if (result != null
|
||||
&& !returnType.isAssignableFrom(result.getClass())) {
|
||||
throw new IllegalArgumentException("Return type " + returnType
|
||||
+ " does not match result "
|
||||
+ result.getClass());
|
||||
throw new ClassCastException("Return type " + returnType
|
||||
+ " does not match result "
|
||||
+ result.getClass());
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -418,9 +417,7 @@ public class Function extends Pointer {
|
||||
// Convert Structures to native pointers
|
||||
if (arg instanceof Structure) {
|
||||
Structure struct = (Structure)arg;
|
||||
if (struct.getAutoWrite()) {
|
||||
struct.write();
|
||||
}
|
||||
struct.autoWrite();
|
||||
if (struct instanceof Structure.ByValue) {
|
||||
// Double-check against the method signature, if available
|
||||
Class ptype = struct.getClass();
|
||||
@@ -476,6 +473,9 @@ public class Function extends Pointer {
|
||||
else if (Pointer[].class == argClass) {
|
||||
return new PointerArray((Pointer[])arg);
|
||||
}
|
||||
else if (NativeMapped[].class.isAssignableFrom(argClass)) {
|
||||
return new NativeMappedArray((NativeMapped[])arg);
|
||||
}
|
||||
else if (Structure[].class.isAssignableFrom(argClass)) {
|
||||
Structure[] ss = (Structure[])arg;
|
||||
Class type = argClass.getComponentType();
|
||||
@@ -483,7 +483,7 @@ public class Function extends Pointer {
|
||||
if (byRef) {
|
||||
Pointer[] pointers = new Pointer[ss.length + 1];
|
||||
for (int i=0;i < ss.length;i++) {
|
||||
pointers[i] = ss[i] != null ? ss[i].getPointer() : null;
|
||||
pointers[i] = ss[i] != null ? ss[i].getPointer() : null;
|
||||
}
|
||||
return new PointerArray(pointers);
|
||||
}
|
||||
@@ -491,39 +491,25 @@ public class Function extends Pointer {
|
||||
throw new IllegalArgumentException("Structure array must have non-zero length");
|
||||
}
|
||||
else if (ss[0] == null) {
|
||||
// Initialize uninitialized arrays of Structure to point
|
||||
// to a single block of memory
|
||||
Structure struct = Structure.newInstance(type);
|
||||
int size = struct.size();
|
||||
Memory m = new Memory(size * ss.length);
|
||||
struct.useMemory(m);
|
||||
Structure[] tmp = struct.toArray(ss.length);
|
||||
for (int si=0;si < ss.length;si++) {
|
||||
ss[si] = tmp[si];
|
||||
}
|
||||
Structure.newInstance(type).toArray(ss);
|
||||
return ss[0].getPointer();
|
||||
}
|
||||
else {
|
||||
Pointer base = ss[0].getPointer();
|
||||
int size = ss[0].size();
|
||||
if (ss[0].getAutoWrite()) {
|
||||
ss[0].write();
|
||||
}
|
||||
ss[0].autoWrite();
|
||||
for (int si=1;si < ss.length;si++) {
|
||||
if (ss[si].getPointer().peer != base.peer + size*si) {
|
||||
String msg = "Structure array elements must use"
|
||||
+ " contiguous memory (at element index " + si + ")";
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
if (ss[si].getAutoWrite()) {
|
||||
ss[si].write();
|
||||
}
|
||||
ss[si].autoWrite();
|
||||
}
|
||||
return base;
|
||||
}
|
||||
}
|
||||
else if (argClass.isArray()){
|
||||
// TODO: handle array of NativeMapped
|
||||
throw new IllegalArgumentException("Unsupported array argument type: "
|
||||
+ argClass.getComponentType());
|
||||
}
|
||||
@@ -547,22 +533,22 @@ public class Function extends Pointer {
|
||||
/**
|
||||
* Call the native function being represented by this object
|
||||
*
|
||||
* @param callingConvention calling convention to be used
|
||||
* @param callFlags calling convention to be used
|
||||
* @param args
|
||||
* Arguments to pass to the native function
|
||||
* @return The value returned by the target native function
|
||||
*/
|
||||
private native int invokeInt(int callingConvention, Object[] args);
|
||||
private native int invokeInt(int callFlags, Object[] args);
|
||||
|
||||
/**
|
||||
* Call the native function being represented by this object
|
||||
*
|
||||
* @param callingConvention calling convention to be used
|
||||
* @param callFlags calling convention to be used
|
||||
* @param args
|
||||
* Arguments to pass to the native function
|
||||
* @return The value returned by the target native function
|
||||
*/
|
||||
private native long invokeLong(int callingConvention, Object[] args);
|
||||
private native long invokeLong(int callFlags, Object[] args);
|
||||
|
||||
/**
|
||||
* Call the native function being represented by this object
|
||||
@@ -578,44 +564,44 @@ public class Function extends Pointer {
|
||||
/**
|
||||
* Call the native function being represented by this object
|
||||
*
|
||||
* @param callingConvention calling convention to be used
|
||||
* @param callFlags calling convention to be used
|
||||
* @param args
|
||||
* Arguments to pass to the native function
|
||||
*/
|
||||
private native void invokeVoid(int callingConvention, Object[] args);
|
||||
private native void invokeVoid(int callFlags, Object[] args);
|
||||
|
||||
/**
|
||||
* Call the native function being represented by this object
|
||||
*
|
||||
* @param callingConvention calling convention to be used
|
||||
* @param callFlags calling convention to be used
|
||||
* @param args
|
||||
* Arguments to pass to the native function
|
||||
* @return The value returned by the target native function
|
||||
*/
|
||||
private native float invokeFloat(int callingConvention, Object[] args);
|
||||
private native float invokeFloat(int callFlags, Object[] args);
|
||||
|
||||
/**
|
||||
* Call the native function being represented by this object
|
||||
*
|
||||
* @param callingConvention calling convention to be used
|
||||
* @param callFlags calling convention to be used
|
||||
* @param args
|
||||
* Arguments to pass to the native function
|
||||
* @return The value returned by the target native function
|
||||
*/
|
||||
private native double invokeDouble(int callingConvention, Object[] args);
|
||||
private native double invokeDouble(int callFlags, Object[] args);
|
||||
|
||||
/**
|
||||
* Call the native function being represented by this object
|
||||
*
|
||||
* @param callingConvention calling convention to be used
|
||||
* @param callFlags calling convention to be used
|
||||
* @param args
|
||||
* Arguments to pass to the native function
|
||||
* @param wide whether the native string uses <code>wchar_t</code>;
|
||||
* if false, <code>char</code> is assumed
|
||||
* @return The value returned by the target native function, as a String
|
||||
*/
|
||||
private String invokeString(int callingConvention, Object[] args, boolean wide) {
|
||||
Pointer ptr = invokePointer(callingConvention, args);
|
||||
private String invokeString(int callFlags, Object[] args, boolean wide) {
|
||||
Pointer ptr = invokePointer(callFlags, args);
|
||||
String s = null;
|
||||
if (ptr != null) {
|
||||
if (wide)
|
||||
@@ -629,36 +615,36 @@ public class Function extends Pointer {
|
||||
/**
|
||||
* Call the native function being represented by this object
|
||||
*
|
||||
* @param callingConvention calling convention to be used
|
||||
* @param callFlags calling convention to be used
|
||||
* @param args
|
||||
* Arguments to pass to the native function
|
||||
* @return The native pointer returned by the target native function
|
||||
*/
|
||||
private native Pointer invokePointer(int callingConvention, Object[] args);
|
||||
private native Pointer invokePointer(int callFlags, Object[] args);
|
||||
|
||||
/**
|
||||
* Call the native function being represented by this object, returning
|
||||
* a struct by value.
|
||||
*
|
||||
* @param callingConvention calling convention to be used
|
||||
* @param callFlags calling convention to be used
|
||||
* @param args
|
||||
* Arguments to pass to the native function
|
||||
* @param result Pre-allocated structure to hold the result
|
||||
* @return The passed-in struct argument
|
||||
*/
|
||||
private native Structure invokeStructure(int callingConvention, Object[] args,
|
||||
private native Structure invokeStructure(int callFlags, Object[] args,
|
||||
Structure result);
|
||||
|
||||
/**
|
||||
* Call the native function being represented by this object, returning
|
||||
* a Java <code>Object</code>.
|
||||
*
|
||||
* @param callingConvention calling convention to be used
|
||||
* @param callFlags calling convention to be used
|
||||
* @param args
|
||||
* Arguments to pass to the native function
|
||||
* @return The returned Java <code>Object</code>
|
||||
*/
|
||||
private native Object invokeObject(int callingConvention, Object[] args);
|
||||
private native Object invokeObject(int callFlags, Object[] args);
|
||||
|
||||
/** Provide a human-readable representation of this object. */
|
||||
public String toString() {
|
||||
@@ -730,9 +716,12 @@ public class Function extends Pointer {
|
||||
* and calling convention.
|
||||
*/
|
||||
public boolean equals(Object o) {
|
||||
if (o instanceof Function) {
|
||||
if (o == this) return true;
|
||||
if (o == null) return false;
|
||||
if (o.getClass() == getClass()) {
|
||||
Function other = (Function)o;
|
||||
return other.callingConvention == this.callingConvention
|
||||
return other.callFlags == this.callFlags
|
||||
&& other.options.equals(this.options)
|
||||
&& other.peer == this.peer;
|
||||
}
|
||||
return false;
|
||||
@@ -784,6 +773,19 @@ public class Function extends Pointer {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class NativeMappedArray extends Memory implements PostCallRead {
|
||||
private final NativeMapped[] original;
|
||||
public NativeMappedArray(NativeMapped[] arg) {
|
||||
super(Native.getNativeSize(arg.getClass(), arg));
|
||||
this.original = arg;
|
||||
Class nativeType = arg.getClass().getComponentType();
|
||||
setValue(0, original, original.getClass());
|
||||
}
|
||||
public void read() {
|
||||
getValue(0, original.getClass(), original);
|
||||
}
|
||||
}
|
||||
|
||||
private static class PointerArray extends Memory implements PostCallRead {
|
||||
private final Pointer[] original;
|
||||
public PointerArray(Pointer[] arg) {
|
||||
|
||||
@@ -22,7 +22,8 @@ package com.sun.jna;
|
||||
public abstract class IntegerType extends Number implements NativeMapped {
|
||||
|
||||
private int size;
|
||||
private Number value;
|
||||
private long value;
|
||||
private Number number;
|
||||
|
||||
/** Create a zero-valued IntegerType. */
|
||||
public IntegerType(int size) {
|
||||
@@ -38,21 +39,22 @@ public abstract class IntegerType extends Number implements NativeMapped {
|
||||
/** Change the value for this data. */
|
||||
public void setValue(long value) {
|
||||
long truncated = value;
|
||||
this.value = value;
|
||||
switch (size) {
|
||||
case 1:
|
||||
truncated = (byte) value;
|
||||
this.value = new Byte((byte) value);
|
||||
this.number = new Byte((byte) value);
|
||||
break;
|
||||
case 2:
|
||||
truncated = (short) value;
|
||||
this.value = new Short((short) value);
|
||||
this.number = new Short((short) value);
|
||||
break;
|
||||
case 4:
|
||||
truncated = (int) value;
|
||||
this.value = new Integer((int) value);
|
||||
this.number = new Integer((int) value);
|
||||
break;
|
||||
case 8:
|
||||
this.value = new Long(value);
|
||||
this.number = new Long(value);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported size: " + size);
|
||||
@@ -69,7 +71,7 @@ public abstract class IntegerType extends Number implements NativeMapped {
|
||||
}
|
||||
|
||||
public Object toNative() {
|
||||
return value;
|
||||
return number;
|
||||
}
|
||||
|
||||
public Object fromNative(Object nativeValue, FromNativeContext context) {
|
||||
@@ -92,35 +94,35 @@ public abstract class IntegerType extends Number implements NativeMapped {
|
||||
}
|
||||
|
||||
public Class nativeType() {
|
||||
return value.getClass();
|
||||
return number.getClass();
|
||||
}
|
||||
|
||||
public int intValue() {
|
||||
return value.intValue();
|
||||
return number.intValue();
|
||||
}
|
||||
|
||||
public long longValue() {
|
||||
return value.longValue();
|
||||
return number.longValue();
|
||||
}
|
||||
|
||||
public float floatValue() {
|
||||
return value.floatValue();
|
||||
return number.floatValue();
|
||||
}
|
||||
|
||||
public double doubleValue() {
|
||||
return value.doubleValue();
|
||||
return number.doubleValue();
|
||||
}
|
||||
|
||||
public boolean equals(Object rhs) {
|
||||
return rhs instanceof IntegerType
|
||||
&& value.equals(((IntegerType) rhs).value);
|
||||
&& number.equals(((IntegerType)rhs).number);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return value.toString();
|
||||
return number.toString();
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return value.hashCode();
|
||||
return number.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/* Copyright (c) 2009 Timothy Wall, All Rights Reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
* <p/>
|
||||
* This library 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 for more details.
|
||||
*/
|
||||
package com.sun.jna;
|
||||
|
||||
/** Exception representing a non-zero error code returned in either
|
||||
<code><a href="http://www.opengroup.org/onlinepubs/009695399/functions/errno.html">errno</a></code> or <code><a href="http://msdn.microsoft.com/en-us/library/ms679360(VS.85).aspx">GetLastError()</a></code>.
|
||||
*/
|
||||
public class LastErrorException extends RuntimeException {
|
||||
private static String formatMessage(int code) {
|
||||
return Platform.isWindows()
|
||||
?"GetLastError() returned " + code
|
||||
:"errno was " + code;
|
||||
}
|
||||
private static String parseMessage(String m) {
|
||||
try {
|
||||
return formatMessage(Integer.parseInt(m));
|
||||
}
|
||||
catch(NumberFormatException e) {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
public int errorCode;
|
||||
public LastErrorException(String msg) {
|
||||
super(parseMessage(msg));
|
||||
try {
|
||||
this.errorCode = Integer.parseInt(msg);
|
||||
}
|
||||
catch(NumberFormatException e) {
|
||||
this.errorCode = -1;
|
||||
}
|
||||
}
|
||||
public LastErrorException(int code) {
|
||||
super(formatMessage(code));
|
||||
this.errorCode = code;
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,7 @@ public interface Library {
|
||||
JNIEnv data structure.
|
||||
*/
|
||||
String OPTION_ALLOW_OBJECTS = "allow-objects";
|
||||
/** Calling convention for the library. */
|
||||
/** Calling convention for the entire library. */
|
||||
String OPTION_CALLING_CONVENTION = "calling-convention";
|
||||
|
||||
static class Handler implements InvocationHandler {
|
||||
@@ -120,20 +120,24 @@ public interface Library {
|
||||
private FunctionMapper functionMapper;
|
||||
private final InvocationMapper invocationMapper;
|
||||
private final Map functions = new WeakHashMap();
|
||||
private final int callingConvention;
|
||||
public Handler(String libname, Class interfaceClass, Map options) {
|
||||
|
||||
if (libname == null || "".equals(libname.trim())) {
|
||||
if ("".equals(libname.trim())) {
|
||||
throw new IllegalArgumentException("Invalid library name \""
|
||||
+ libname + "\"");
|
||||
}
|
||||
|
||||
this.nativeLibrary = NativeLibrary.getInstance(libname);
|
||||
this.interfaceClass = interfaceClass;
|
||||
this.options = options;
|
||||
this.callingConvention =
|
||||
options = new HashMap(options);
|
||||
int callingConvention =
|
||||
AltCallingConvention.class.isAssignableFrom(interfaceClass)
|
||||
? Function.ALT_CONVENTION : Function.C_CONVENTION;
|
||||
if (options.get(OPTION_CALLING_CONVENTION) == null) {
|
||||
options.put(OPTION_CALLING_CONVENTION,
|
||||
new Integer(callingConvention));
|
||||
}
|
||||
this.options = options;
|
||||
this.nativeLibrary = NativeLibrary.getInstance(libname, options);
|
||||
functionMapper = (FunctionMapper)options.get(OPTION_FUNCTION_MAPPER);
|
||||
if (functionMapper == null) {
|
||||
// backward compatibility; passed-in map is itself the name map
|
||||
@@ -196,7 +200,7 @@ public interface Library {
|
||||
// Just in case the function mapper screwed up
|
||||
methodName = method.getName();
|
||||
}
|
||||
f.function = nativeLibrary.getFunction(methodName, callingConvention);
|
||||
f.function = nativeLibrary.getFunction(methodName, method);
|
||||
f.options = new HashMap(this.options);
|
||||
f.options.put(Function.OPTION_INVOKING_METHOD, method);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
package com.sun.jna;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
/**
|
||||
* A <code>Pointer</code> to memory obtained from the native heap via a
|
||||
@@ -36,8 +37,17 @@ import java.nio.ByteBuffer;
|
||||
*/
|
||||
public class Memory extends Pointer {
|
||||
|
||||
private static Map buffers = new WeakHashMap();
|
||||
|
||||
protected long size; // Size of the malloc'ed space
|
||||
|
||||
/** Force cleanup of memory that has associated NIO Buffers which have
|
||||
been GC'd.
|
||||
*/
|
||||
public static void purge() {
|
||||
buffers.size();
|
||||
}
|
||||
|
||||
/** Provide a view into the original memory. */
|
||||
private class SharedMemory extends Memory {
|
||||
public SharedMemory(long offset) {
|
||||
@@ -105,17 +115,22 @@ public class Memory extends Pointer {
|
||||
if (byteBoundary <= 0) {
|
||||
throw new IllegalArgumentException("Byte boundary must be positive: " + byteBoundary);
|
||||
}
|
||||
long mask = ~((long)byteBoundary - 1);
|
||||
|
||||
if ((peer & ~mask) != peer) {
|
||||
long newPeer = (peer + ~mask) & mask;
|
||||
long newSize = peer + size - newPeer;
|
||||
if (newSize <= 0) {
|
||||
throw new IllegalArgumentException("Insufficient memory to align to the requested boundary");
|
||||
for (int i=0;i < 32;i++) {
|
||||
if (byteBoundary == (1<<i)) {
|
||||
long mask = ~((long)byteBoundary - 1);
|
||||
|
||||
if ((peer & mask) != peer) {
|
||||
long newPeer = (peer + byteBoundary - 1) & mask;
|
||||
long newSize = peer + size - newPeer;
|
||||
if (newSize <= 0) {
|
||||
throw new IllegalArgumentException("Insufficient memory to align to the requested boundary");
|
||||
}
|
||||
return (Memory)share(newPeer - peer, newSize);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
return (Memory)share(newPeer - peer, newSize);
|
||||
}
|
||||
return this;
|
||||
throw new IllegalArgumentException("Byte boundary must be a power of two");
|
||||
}
|
||||
|
||||
protected void finalize() {
|
||||
@@ -487,7 +502,11 @@ public class Memory extends Pointer {
|
||||
*/
|
||||
public ByteBuffer getByteBuffer(long offset, long length) {
|
||||
boundsCheck(offset, length);
|
||||
return super.getByteBuffer(offset, length);
|
||||
ByteBuffer b = super.getByteBuffer(offset, length);
|
||||
// Ensure this Memory object will not be GC'd (and its memory freed)
|
||||
// if the Buffer is still extant.
|
||||
buffers.put(b, this);
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -17,6 +17,7 @@ package com.sun.jna;
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -29,7 +30,8 @@ import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* Provides management of native library resources. One instance of this
|
||||
* class corresponds to a single loaded native library.
|
||||
* class corresponds to a single loaded native library. May also be used
|
||||
* to map to the current process (see {@link NativeLibrary#getProcess()}).
|
||||
* <p>
|
||||
* <b>Library Search Paths</b>
|
||||
* A search for a given library will scan the following locations:
|
||||
@@ -45,10 +47,9 @@ public class NativeLibrary {
|
||||
private final String libraryName;
|
||||
private final String libraryPath;
|
||||
private final Map functions = new HashMap();
|
||||
private final int callingConvention;
|
||||
private final Map options;
|
||||
final int callFlags;
|
||||
final Map options;
|
||||
|
||||
private static WeakReference currentProcess;
|
||||
private static final Map libraries = new HashMap();
|
||||
private static final Map searchPaths = Collections.synchronizedMap(new HashMap());
|
||||
private static final List librarySearchPath = new LinkedList();
|
||||
@@ -60,6 +61,10 @@ public class NativeLibrary {
|
||||
throw new Error("Native library not initialized");
|
||||
}
|
||||
|
||||
private static String functionKey(String name, int flags) {
|
||||
return name + "|" + flags;
|
||||
}
|
||||
|
||||
private NativeLibrary(String libraryName, String libraryPath, long handle, Map options) {
|
||||
this.libraryName = getLibraryName(libraryName);
|
||||
this.libraryPath = libraryPath;
|
||||
@@ -67,7 +72,7 @@ public class NativeLibrary {
|
||||
Object option = options.get(Library.OPTION_CALLING_CONVENTION);
|
||||
int callingConvention = option instanceof Integer
|
||||
? ((Integer)option).intValue() : Function.C_CONVENTION;
|
||||
this.callingConvention = callingConvention;
|
||||
this.callFlags = callingConvention;
|
||||
this.options = options;
|
||||
|
||||
// Special workaround for w32 kernel32.GetLastError
|
||||
@@ -79,7 +84,7 @@ public class NativeLibrary {
|
||||
return new Integer(Native.getLastError());
|
||||
}
|
||||
};
|
||||
functions.put("GetLastError", f);
|
||||
functions.put(functionKey("GetLastError", callFlags), f);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -109,8 +114,8 @@ public class NativeLibrary {
|
||||
long handle = 0;
|
||||
//
|
||||
// Only search user specified paths first. This will also fall back
|
||||
// to dlopen/LoadLibrary() since findLibraryPath returns the mapped name
|
||||
// if it cannot find the library.
|
||||
// to dlopen/LoadLibrary() since findLibraryPath returns the mapped
|
||||
// name if it cannot find the library.
|
||||
//
|
||||
try {
|
||||
handle = open(libraryPath);
|
||||
@@ -206,46 +211,57 @@ public class NativeLibrary {
|
||||
* Library}).
|
||||
*/
|
||||
public static final NativeLibrary getInstance(String libraryName, Map options) {
|
||||
if (libraryName == null)
|
||||
throw new NullPointerException("Library name may not be null");
|
||||
options = new HashMap(options);
|
||||
if (options.get(Library.OPTION_CALLING_CONVENTION) == null) {
|
||||
options.put(Library.OPTION_CALLING_CONVENTION, new Integer(Function.C_CONVENTION));
|
||||
}
|
||||
|
||||
synchronized (libraries) {
|
||||
WeakReference ref = (WeakReference)libraries.get(libraryName);
|
||||
WeakReference ref = (WeakReference)libraries.get(libraryName + options);
|
||||
NativeLibrary library = ref != null ? (NativeLibrary)ref.get() : null;
|
||||
|
||||
if (library == null) {
|
||||
library = loadLibrary(libraryName, options);
|
||||
if (libraryName == null) {
|
||||
library = new NativeLibrary("<process>", null, open(null), options);
|
||||
}
|
||||
else {
|
||||
library = loadLibrary(libraryName, options);
|
||||
}
|
||||
ref = new WeakReference(library);
|
||||
libraries.put(library.getName(), ref);
|
||||
libraries.put(library.getFile().getAbsolutePath(), ref);
|
||||
libraries.put(library.getFile().getName(), ref);
|
||||
libraries.put(library.getName() + options, ref);
|
||||
File file = library.getFile();
|
||||
if (file != null) {
|
||||
libraries.put(file.getAbsolutePath() + options, ref);
|
||||
libraries.put(file.getName() + options, ref);
|
||||
}
|
||||
}
|
||||
return library;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of NativeLibrary which refers to the current process.
|
||||
* This is useful for accessing functions which were already mapped by some
|
||||
* other mechanism, without having to reference or even know the exact
|
||||
* name of the native library.
|
||||
* Returns an instance of NativeLibrary which refers to the current
|
||||
* process. This is useful for accessing functions which were already
|
||||
* mapped by some other mechanism, without having to reference or even
|
||||
* know the exact name of the native library.
|
||||
*/
|
||||
public static synchronized final NativeLibrary getProcess() {
|
||||
NativeLibrary library = null;
|
||||
if (currentProcess != null) {
|
||||
library = (NativeLibrary) currentProcess.get();
|
||||
}
|
||||
|
||||
if (library == null) {
|
||||
long handle = open(null);
|
||||
library = new NativeLibrary("<process>", null, handle, Collections.EMPTY_MAP);
|
||||
currentProcess = new WeakReference(library);
|
||||
}
|
||||
|
||||
return library;
|
||||
return getInstance(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a path to search for the specified library, ahead of any system paths
|
||||
* Returns an instance of NativeLibrary which refers to the current
|
||||
* process. This is useful for accessing functions which were already
|
||||
* mapped by some other mechanism, without having to reference or even
|
||||
* know the exact name of the native library.
|
||||
*/
|
||||
public static synchronized final NativeLibrary getProcess(Map options) {
|
||||
return getInstance(null, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a path to search for the specified library, ahead of any system
|
||||
* paths.
|
||||
*
|
||||
* @param libraryName The name of the library to use the path for
|
||||
* @param path The path to use when trying to load the library
|
||||
@@ -263,41 +279,62 @@ public class NativeLibrary {
|
||||
}
|
||||
/**
|
||||
* Create a new {@link Function} that is linked with a native
|
||||
* function that follows the standard "C" calling convention.
|
||||
* function that follows the NativeLibrary's calling convention.
|
||||
*
|
||||
* <p>The allocated instance represents a pointer to the named native
|
||||
* function from the library, called with the standard "C" calling
|
||||
* convention.
|
||||
* function from the library.
|
||||
*
|
||||
* @param functionName
|
||||
* Name of the native function to be linked with
|
||||
* @throws UnsatisfiedLinkError if the function is not found
|
||||
*/
|
||||
public Function getFunction(String functionName) {
|
||||
return getFunction(functionName, callingConvention);
|
||||
return getFunction(functionName, callFlags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link Function} that is linked with a native
|
||||
* function that follows the NativeLibrary's calling convention.
|
||||
*
|
||||
* <p>The allocated instance represents a pointer to the named native
|
||||
* function from the library.
|
||||
*
|
||||
* @param name
|
||||
* Name of the native function to be linked with
|
||||
* @param method
|
||||
* Method to which the native function is to be mapped
|
||||
* @throws UnsatisfiedLinkError if the function is not found
|
||||
*/
|
||||
Function getFunction(String name, Method method) {
|
||||
int flags = this.callFlags;
|
||||
Class[] etypes = method.getExceptionTypes();
|
||||
for (int i=0;i < etypes.length;i++) {
|
||||
if (LastErrorException.class.isAssignableFrom(etypes[i])) {
|
||||
flags |= Function.THROW_LAST_ERROR;
|
||||
}
|
||||
}
|
||||
return getFunction(name, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new @{link Function} that is linked with a native
|
||||
* function that follows a given calling convention.
|
||||
*
|
||||
* <p>The allocated instance represents a pointer to the named native
|
||||
* function from the library, called with the named calling convention.
|
||||
* function that follows a given calling flags.
|
||||
*
|
||||
* @param functionName
|
||||
* Name of the native function to be linked with
|
||||
* @param callingConvention
|
||||
* Calling convention used by the native function
|
||||
* @param callFlags
|
||||
* Flags affecting the function invocation
|
||||
* @throws UnsatisfiedLinkError if the function is not found
|
||||
*/
|
||||
public Function getFunction(String functionName, int callingConvention) {
|
||||
public Function getFunction(String functionName, int callFlags) {
|
||||
if (functionName == null)
|
||||
throw new NullPointerException("Function name may not be null");
|
||||
synchronized (functions) {
|
||||
Function function = (Function) functions.get(functionName);
|
||||
String key = functionKey(functionName, callFlags);
|
||||
Function function = (Function) functions.get(key);
|
||||
if (function == null) {
|
||||
function = new Function(this, functionName, callingConvention);
|
||||
functions.put(functionName, function);
|
||||
function = new Function(this, functionName, callFlags);
|
||||
functions.put(key, function);
|
||||
}
|
||||
return function;
|
||||
}
|
||||
@@ -357,11 +394,11 @@ public class NativeLibrary {
|
||||
|
||||
public void dispose() {
|
||||
synchronized(libraries) {
|
||||
libraries.remove(getName());
|
||||
File path = getFile();
|
||||
if (path != null) {
|
||||
libraries.remove(path.getAbsolutePath());
|
||||
libraries.remove(path.getName());
|
||||
libraries.remove(getName() + options);
|
||||
File file = getFile();
|
||||
if (file != null) {
|
||||
libraries.remove(file.getAbsolutePath() + options);
|
||||
libraries.remove(file.getName() + options);
|
||||
}
|
||||
}
|
||||
synchronized(this) {
|
||||
|
||||
@@ -11,14 +11,15 @@ package com.sun.jna;
|
||||
|
||||
/** Provide simplified platform information. */
|
||||
public final class Platform {
|
||||
private static final int UNSPECIFIED = -1;
|
||||
private static final int MAC = 0;
|
||||
private static final int LINUX = 1;
|
||||
private static final int WINDOWS = 2;
|
||||
private static final int SOLARIS = 3;
|
||||
private static final int FREEBSD = 4;
|
||||
private static final int OPENBSD = 5;
|
||||
private static final int WINDOWSCE = 6;
|
||||
public static final int UNSPECIFIED = -1;
|
||||
public static final int MAC = 0;
|
||||
public static final int LINUX = 1;
|
||||
public static final int WINDOWS = 2;
|
||||
public static final int SOLARIS = 3;
|
||||
public static final int FREEBSD = 4;
|
||||
public static final int OPENBSD = 5;
|
||||
public static final int WINDOWSCE = 6;
|
||||
|
||||
private static final int osType;
|
||||
|
||||
static {
|
||||
@@ -49,6 +50,9 @@ public final class Platform {
|
||||
}
|
||||
}
|
||||
private Platform() { }
|
||||
public static final int getOSType() {
|
||||
return osType;
|
||||
}
|
||||
public static final boolean isMac() {
|
||||
return osType == MAC;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
package com.sun.jna;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.reflect.Array;
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
@@ -73,7 +75,7 @@ public class Pointer {
|
||||
}
|
||||
|
||||
/** Zero memory for the given number of bytes. */
|
||||
void clear(long size) {
|
||||
public void clear(long size) {
|
||||
setMemory(0, size, (byte)0);
|
||||
}
|
||||
|
||||
@@ -87,9 +89,9 @@ public class Pointer {
|
||||
* equal. Returns false otherwise.
|
||||
*/
|
||||
public boolean equals(Object o) {
|
||||
if (o == null)
|
||||
return peer == 0;
|
||||
return (o instanceof Pointer) && ((Pointer)o).peer == peer;
|
||||
if (o == this) return true;
|
||||
if (o == null) return false;
|
||||
return o instanceof Pointer && ((Pointer)o).peer == peer;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -374,6 +376,180 @@ public class Pointer {
|
||||
// Java type read methods
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Object getValue(long offset, Class type, Object currentValue) {
|
||||
Object result = null;
|
||||
if (Structure.class.isAssignableFrom(type)) {
|
||||
Structure s = (Structure)currentValue;
|
||||
if (Structure.ByReference.class.isAssignableFrom(type)) {
|
||||
s = Structure.updateStructureByReference(type, s, getPointer(offset));
|
||||
}
|
||||
else {
|
||||
s.useMemory(this, (int)offset);
|
||||
s.read();
|
||||
}
|
||||
result = s;
|
||||
}
|
||||
else if (type == boolean.class || type == Boolean.class) {
|
||||
result = Function.valueOf(getInt(offset) != 0);
|
||||
}
|
||||
else if (type == byte.class || type == Byte.class) {
|
||||
result = new Byte(getByte(offset));
|
||||
}
|
||||
else if (type == short.class || type == Short.class) {
|
||||
result = new Short(getShort(offset));
|
||||
}
|
||||
else if (type == char.class || type == Character.class) {
|
||||
result = new Character(getChar(offset));
|
||||
}
|
||||
else if (type == int.class || type == Integer.class) {
|
||||
result = new Integer(getInt(offset));
|
||||
}
|
||||
else if (type == long.class || type == Long.class) {
|
||||
result = new Long(getLong(offset));
|
||||
}
|
||||
else if (type == float.class || type == Float.class) {
|
||||
result=new Float(getFloat(offset));
|
||||
}
|
||||
else if (type == double.class || type == Double.class) {
|
||||
result = new Double(getDouble(offset));
|
||||
}
|
||||
else if (Pointer.class.isAssignableFrom(type)) {
|
||||
Pointer p = getPointer(offset);
|
||||
if (p != null) {
|
||||
Pointer oldp = currentValue instanceof Pointer
|
||||
? (Pointer)currentValue : null;
|
||||
if (oldp == null || p.peer != oldp.peer)
|
||||
result = p;
|
||||
else
|
||||
result = oldp;
|
||||
}
|
||||
}
|
||||
else if (type == String.class) {
|
||||
Pointer p = getPointer(offset);
|
||||
result = p != null ? p.getString(0) : null;
|
||||
}
|
||||
else if (type == WString.class) {
|
||||
Pointer p = getPointer(offset);
|
||||
result = p != null ? new WString(p.getString(0, true)) : null;
|
||||
}
|
||||
else if (Callback.class.isAssignableFrom(type)) {
|
||||
// Overwrite the Java memory if the native pointer is a different
|
||||
// function pointer.
|
||||
Pointer fp = getPointer(offset);
|
||||
if (fp == null) {
|
||||
result = null;
|
||||
}
|
||||
else {
|
||||
Callback cb = (Callback)currentValue;
|
||||
Pointer oldfp = CallbackReference.getFunctionPointer(cb);
|
||||
if (!fp.equals(oldfp)) {
|
||||
cb = CallbackReference.getCallback(type, fp);
|
||||
}
|
||||
result = cb;
|
||||
}
|
||||
}
|
||||
else if (Buffer.class.isAssignableFrom(type)) {
|
||||
Pointer bp = getPointer(offset);
|
||||
if (bp == null) {
|
||||
result = null;
|
||||
}
|
||||
else {
|
||||
Pointer oldbp = currentValue == null ? null
|
||||
: Native.getDirectBufferPointer((Buffer)currentValue);
|
||||
if (oldbp == null || !oldbp.equals(bp)) {
|
||||
throw new IllegalStateException("Can't autogenerate a direct buffers on memory read");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (NativeMapped.class.isAssignableFrom(type)) {
|
||||
NativeMapped nm = (NativeMapped)currentValue;
|
||||
if (nm != null) {
|
||||
Object value = getValue(offset, nm.nativeType(), null);
|
||||
nm.fromNative(value, new FromNativeContext(type));
|
||||
}
|
||||
else {
|
||||
NativeMappedConverter tc = NativeMappedConverter.getInstance(type);
|
||||
Object value = getValue(offset, tc.nativeType(), null);
|
||||
result = tc.fromNative(value, new FromNativeContext(type));
|
||||
}
|
||||
}
|
||||
else if (type.isArray()) {
|
||||
result = currentValue;
|
||||
if (result == null) {
|
||||
throw new IllegalStateException("Need an initialized array");
|
||||
}
|
||||
getArrayValue(offset, result, type.getComponentType());
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Reading \""
|
||||
+ type + "\" from memory is not supported");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void getArrayValue(long offset, Object o, Class cls) {
|
||||
int length = 0;
|
||||
length = Array.getLength(o);
|
||||
Object result = o;
|
||||
|
||||
if (cls == byte.class) {
|
||||
read(offset, (byte[])result, 0, length);
|
||||
}
|
||||
else if (cls == short.class) {
|
||||
read(offset, (short[])result, 0, length);
|
||||
}
|
||||
else if (cls == char.class) {
|
||||
read(offset, (char[])result, 0, length);
|
||||
}
|
||||
else if (cls == int.class) {
|
||||
read(offset, (int[])result, 0, length);
|
||||
}
|
||||
else if (cls == long.class) {
|
||||
read(offset, (long[])result, 0, length);
|
||||
}
|
||||
else if (cls == float.class) {
|
||||
read(offset, (float[])result, 0, length);
|
||||
}
|
||||
else if (cls == double.class) {
|
||||
read(offset, (double[])result, 0, length);
|
||||
}
|
||||
else if (Pointer.class.isAssignableFrom(cls)) {
|
||||
read(offset, (Pointer[])result, 0, length);
|
||||
}
|
||||
else if (Structure.class.isAssignableFrom(cls)) {
|
||||
Structure[] sarray = (Structure[])result;
|
||||
if (Structure.ByReference.class.isAssignableFrom(cls)) {
|
||||
Pointer[] parray = getPointerArray(offset, sarray.length);
|
||||
for (int i=0;i < sarray.length;i++) {
|
||||
sarray[i] = Structure.updateStructureByReference(cls, sarray[i], parray[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i=0;i < sarray.length;i++) {
|
||||
if (sarray[i] == null) {
|
||||
sarray[i] = Structure.newInstance(cls);
|
||||
}
|
||||
sarray[i].useMemory(this, (int)(offset + i * sarray[i].size()));
|
||||
sarray[i].read();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (NativeMapped.class.isAssignableFrom(cls)) {
|
||||
NativeMapped[] array = (NativeMapped[])result;
|
||||
NativeMappedConverter tc = NativeMappedConverter.getInstance(cls);
|
||||
int size = Native.getNativeSize(result.getClass(), result) / array.length;
|
||||
for (int i=0;i < array.length;i++) {
|
||||
Object value = getValue(offset + size*i, tc.nativeType(), array[i]);
|
||||
array[i] = (NativeMapped)tc.fromNative(value, new FromNativeContext(cls));
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Reading array of "
|
||||
+ cls
|
||||
+ " from memory not supported");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indirect the native pointer as a pointer to <code>byte</code>. This is
|
||||
* equivalent to the expression
|
||||
@@ -657,6 +833,144 @@ v * @param wide whether to convert from a wide or standard C string
|
||||
// Java type write methods
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void setValue(long offset, Object value, Class type) {
|
||||
// Set the value at the offset according to its type
|
||||
if (type == boolean.class || type == Boolean.class) {
|
||||
setInt(offset, Boolean.TRUE.equals(value) ? -1 : 0);
|
||||
}
|
||||
else if (type == byte.class || type == Byte.class) {
|
||||
setByte(offset, value == null ? 0 : ((Byte)value).byteValue());
|
||||
}
|
||||
else if (type == short.class || type == Short.class) {
|
||||
setShort(offset, value == null ? 0 : ((Short)value).shortValue());
|
||||
}
|
||||
else if (type == char.class || type == Character.class) {
|
||||
setChar(offset, value == null ? 0 : ((Character)value).charValue());
|
||||
}
|
||||
else if (type == int.class || type == Integer.class) {
|
||||
setInt(offset, value == null ? 0 : ((Integer)value).intValue());
|
||||
}
|
||||
else if (type == long.class || type == Long.class) {
|
||||
setLong(offset, value == null ? 0 : ((Long)value).longValue());
|
||||
}
|
||||
else if (type == float.class || type == Float.class) {
|
||||
setFloat(offset, value == null ? 0f : ((Float)value).floatValue());
|
||||
}
|
||||
else if (type == double.class || type == Double.class) {
|
||||
setDouble(offset, value == null ? 0.0 : ((Double)value).doubleValue());
|
||||
}
|
||||
else if (type == Pointer.class) {
|
||||
setPointer(offset, (Pointer)value);
|
||||
}
|
||||
else if (type == String.class) {
|
||||
setPointer(offset, (Pointer)value);
|
||||
}
|
||||
else if (type == WString.class) {
|
||||
setPointer(offset, (Pointer)value);
|
||||
}
|
||||
else if (Structure.class.isAssignableFrom(type)) {
|
||||
Structure s = (Structure)value;
|
||||
if (Structure.ByReference.class.isAssignableFrom(type)) {
|
||||
setPointer(offset, s == null ? null : s.getPointer());
|
||||
if (s != null) {
|
||||
s.autoWrite();
|
||||
}
|
||||
}
|
||||
else {
|
||||
s.useMemory(this, (int)offset);
|
||||
s.write();
|
||||
}
|
||||
}
|
||||
else if (Callback.class.isAssignableFrom(type)) {
|
||||
setPointer(offset, CallbackReference.getFunctionPointer((Callback)value));
|
||||
}
|
||||
else if (Buffer.class.isAssignableFrom(type)) {
|
||||
Pointer p = value == null ? null
|
||||
: Native.getDirectBufferPointer((Buffer)value);
|
||||
setPointer(offset, p);
|
||||
}
|
||||
else if (NativeMapped.class.isAssignableFrom(type)) {
|
||||
NativeMappedConverter tc = NativeMappedConverter.getInstance(type);
|
||||
Class nativeType = tc.nativeType();
|
||||
setValue(offset, tc.toNative(value, new ToNativeContext()), nativeType);
|
||||
}
|
||||
else if (type.isArray()) {
|
||||
setArrayValue(offset, value, type.getComponentType());
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Writing " + type + " to memory is not supported");
|
||||
}
|
||||
}
|
||||
|
||||
private void setArrayValue(long offset, Object value, Class cls) {
|
||||
if (cls == byte.class) {
|
||||
byte[] buf = (byte[])value;
|
||||
write(offset, buf, 0, buf.length);
|
||||
}
|
||||
else if (cls == short.class) {
|
||||
short[] buf = (short[])value;
|
||||
write(offset, buf, 0, buf.length);
|
||||
}
|
||||
else if (cls == char.class) {
|
||||
char[] buf = (char[])value;
|
||||
write(offset, buf, 0, buf.length);
|
||||
}
|
||||
else if (cls == int.class) {
|
||||
int[] buf = (int[])value;
|
||||
write(offset, buf, 0, buf.length);
|
||||
}
|
||||
else if (cls == long.class) {
|
||||
long[] buf = (long[])value;
|
||||
write(offset, buf, 0, buf.length);
|
||||
}
|
||||
else if (cls == float.class) {
|
||||
float[] buf = (float[])value;
|
||||
write(offset, buf, 0, buf.length);
|
||||
}
|
||||
else if (cls == double.class) {
|
||||
double[] buf = (double[])value;
|
||||
write(offset, buf, 0, buf.length);
|
||||
}
|
||||
else if (Pointer.class.isAssignableFrom(cls)) {
|
||||
Pointer[] buf = (Pointer[])value;
|
||||
write(offset, buf, 0, buf.length);
|
||||
}
|
||||
else if (Structure.class.isAssignableFrom(cls)) {
|
||||
Structure[] sbuf = (Structure[])value;
|
||||
if (Structure.ByReference.class.isAssignableFrom(cls)) {
|
||||
Pointer[] buf = new Pointer[sbuf.length];
|
||||
for (int i=0;i < sbuf.length;i++) {
|
||||
buf[i] = sbuf[i] == null ? null : sbuf[i].getPointer();
|
||||
sbuf[i].write();
|
||||
}
|
||||
write(offset, buf, 0, buf.length);
|
||||
}
|
||||
else {
|
||||
for (int i=0;i < sbuf.length;i++) {
|
||||
if (sbuf[i] == null) {
|
||||
sbuf[i] = Structure.newInstance(cls);
|
||||
}
|
||||
sbuf[i].useMemory(this, (int)(offset + i * sbuf[i].size()));
|
||||
sbuf[i].write();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (NativeMapped.class.isAssignableFrom(cls)) {
|
||||
NativeMapped[] buf = (NativeMapped[])value;
|
||||
NativeMappedConverter tc = NativeMappedConverter.getInstance(cls);
|
||||
Class nativeType = tc.nativeType();
|
||||
int size = Native.getNativeSize(value.getClass(), value) / buf.length;
|
||||
for (int i=0;i < buf.length;i++) {
|
||||
Object element = tc.toNative(buf[i], new ToNativeContext());
|
||||
setValue(offset + i*size, element, nativeType);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Writing array of "
|
||||
+ cls + " to memory not supported");
|
||||
}
|
||||
}
|
||||
|
||||
/** Write <code>value</code> to the requested bank of memory.
|
||||
* @param offset byte offset from pointer to start
|
||||
* @param length number of bytes to write
|
||||
|
||||
@@ -87,6 +87,7 @@ public abstract class PointerType implements NativeMapped {
|
||||
* equal by default.
|
||||
*/
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) return true;
|
||||
if (o instanceof PointerType) {
|
||||
Pointer p = ((PointerType)o).getPointer();
|
||||
if (pointer == null)
|
||||
|
||||
@@ -14,8 +14,10 @@ import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.nio.Buffer;
|
||||
import java.util.AbstractCollection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
@@ -122,6 +124,7 @@ public abstract class Structure {
|
||||
private List fieldOrder;
|
||||
private boolean autoRead = true;
|
||||
private boolean autoWrite = true;
|
||||
private Structure[] array;
|
||||
|
||||
protected Structure() {
|
||||
this((Pointer)null);
|
||||
@@ -287,10 +290,37 @@ public abstract class Structure {
|
||||
// Data synchronization methods
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Keep track of what is currently being read to avoid redundant reads
|
||||
// (avoids problems with circular references).
|
||||
private static Set reading = new HashSet();
|
||||
private static Set writing = new HashSet();
|
||||
// Keep track of what is currently being read/written to avoid redundant
|
||||
// reads (avoids problems with circular references).
|
||||
private static final ThreadLocal busy = new ThreadLocal() {
|
||||
/** Avoid using a hash-based implementation since the hash code
|
||||
will change if structure field values change.
|
||||
*/
|
||||
class StructureSet extends AbstractCollection implements Set {
|
||||
private Collection list = new ArrayList();
|
||||
public int size() { return list.size(); }
|
||||
public boolean contains(Object o) {
|
||||
for (Iterator i=iterator();i.hasNext();) {
|
||||
if (o == i.next())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public boolean add(Object o) {
|
||||
if (!contains(o))
|
||||
return list.add(o);
|
||||
return true;
|
||||
}
|
||||
public Iterator iterator() { return list.iterator(); }
|
||||
}
|
||||
protected synchronized Object initialValue() {
|
||||
return new StructureSet();
|
||||
}
|
||||
};
|
||||
Set busy() {
|
||||
return (Set)busy.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the fields of the struct from native memory
|
||||
*/
|
||||
@@ -300,20 +330,17 @@ public abstract class Structure {
|
||||
// have to explicitly call allocateMemory in a ctor
|
||||
ensureAllocated();
|
||||
// Avoid recursive reads
|
||||
synchronized(reading) {
|
||||
if (reading.contains(this))
|
||||
return;
|
||||
reading.add(this);
|
||||
if (busy().contains(this)) {
|
||||
return;
|
||||
}
|
||||
busy().add(this);
|
||||
try {
|
||||
for (Iterator i=structFields.values().iterator();i.hasNext();) {
|
||||
readField((StructField)i.next());
|
||||
}
|
||||
}
|
||||
finally {
|
||||
synchronized(reading) {
|
||||
reading.remove(this);
|
||||
}
|
||||
busy().remove(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,9 +398,7 @@ public abstract class Structure {
|
||||
s = newInstance(type);
|
||||
s.useMemory(address);
|
||||
}
|
||||
if (s.getAutoRead()) {
|
||||
s.read();
|
||||
}
|
||||
s.autoRead();
|
||||
}
|
||||
return s;
|
||||
}
|
||||
@@ -388,19 +413,20 @@ public abstract class Structure {
|
||||
int offset = structField.offset;
|
||||
|
||||
// Determine the type of the field
|
||||
Class nativeType = structField.type;
|
||||
Class fieldType = structField.type;
|
||||
FromNativeConverter readConverter = structField.readConverter;
|
||||
if (readConverter != null) {
|
||||
nativeType = readConverter.nativeType();
|
||||
fieldType = readConverter.nativeType();
|
||||
}
|
||||
// Get the current value only for types which might need to be preserved
|
||||
Object currentValue = (Structure.class.isAssignableFrom(nativeType)
|
||||
|| Callback.class.isAssignableFrom(nativeType)
|
||||
|| Buffer.class.isAssignableFrom(nativeType)
|
||||
|| Pointer.class.isAssignableFrom(nativeType)
|
||||
|| nativeType.isArray())
|
||||
Object currentValue = (Structure.class.isAssignableFrom(fieldType)
|
||||
|| Callback.class.isAssignableFrom(fieldType)
|
||||
|| Buffer.class.isAssignableFrom(fieldType)
|
||||
|| Pointer.class.isAssignableFrom(fieldType)
|
||||
|| fieldType.isArray())
|
||||
? getField(structField) : null;
|
||||
Object result = readValue(offset, nativeType, currentValue);
|
||||
Object result = memory.getValue(offset, fieldType, currentValue);
|
||||
// TODO: process against current value here
|
||||
|
||||
if (readConverter != null) {
|
||||
result = readConverter.fromNative(result, structField.context);
|
||||
@@ -411,170 +437,6 @@ public abstract class Structure {
|
||||
return result;
|
||||
}
|
||||
|
||||
private Object readValue(int offset, Class nativeType, Object currentValue) {
|
||||
|
||||
Object result = null;
|
||||
if (Structure.class.isAssignableFrom(nativeType)) {
|
||||
Structure s = (Structure)currentValue;
|
||||
if (ByReference.class.isAssignableFrom(nativeType)) {
|
||||
s = updateStructureByReference(nativeType, s, memory.getPointer(offset));
|
||||
}
|
||||
else {
|
||||
s.useMemory(memory, offset);
|
||||
s.read();
|
||||
}
|
||||
result = s;
|
||||
}
|
||||
else if (nativeType == boolean.class || nativeType == Boolean.class) {
|
||||
result = Function.valueOf(memory.getInt(offset) != 0);
|
||||
}
|
||||
else if (nativeType == byte.class || nativeType == Byte.class) {
|
||||
result = new Byte(memory.getByte(offset));
|
||||
}
|
||||
else if (nativeType == short.class || nativeType == Short.class) {
|
||||
result = new Short(memory.getShort(offset));
|
||||
}
|
||||
else if (nativeType == char.class || nativeType == Character.class) {
|
||||
result = new Character(memory.getChar(offset));
|
||||
}
|
||||
else if (nativeType == int.class || nativeType == Integer.class) {
|
||||
result = new Integer(memory.getInt(offset));
|
||||
}
|
||||
else if (nativeType == long.class || nativeType == Long.class) {
|
||||
result = new Long(memory.getLong(offset));
|
||||
}
|
||||
else if (nativeType == float.class || nativeType == Float.class) {
|
||||
result=new Float(memory.getFloat(offset));
|
||||
}
|
||||
else if (nativeType == double.class || nativeType == Double.class) {
|
||||
result = new Double(memory.getDouble(offset));
|
||||
}
|
||||
else if (nativeType == Pointer.class) {
|
||||
Pointer p = memory.getPointer(offset);
|
||||
if (p != null) {
|
||||
Pointer oldp = currentValue instanceof Pointer
|
||||
? (Pointer)currentValue : null;
|
||||
if (oldp == null || p.peer != oldp.peer)
|
||||
result = p;
|
||||
else
|
||||
result = oldp;
|
||||
}
|
||||
}
|
||||
else if (nativeType == String.class) {
|
||||
Pointer p = memory.getPointer(offset);
|
||||
result = p != null ? p.getString(0) : null;
|
||||
}
|
||||
else if (nativeType == WString.class) {
|
||||
Pointer p = memory.getPointer(offset);
|
||||
result = p != null ? new WString(p.getString(0, true)) : null;
|
||||
}
|
||||
else if (Callback.class.isAssignableFrom(nativeType)) {
|
||||
// Overwrite the Java memory if the native pointer is a different
|
||||
// function pointer.
|
||||
Pointer fp = memory.getPointer(offset);
|
||||
if (fp == null) {
|
||||
result = null;
|
||||
}
|
||||
else {
|
||||
Callback cb = (Callback)currentValue;
|
||||
Pointer oldfp = CallbackReference.getFunctionPointer(cb);
|
||||
if (!fp.equals(oldfp)) {
|
||||
cb = CallbackReference.getCallback(nativeType, fp);
|
||||
}
|
||||
result = cb;
|
||||
}
|
||||
}
|
||||
else if (Buffer.class.isAssignableFrom(nativeType)) {
|
||||
Pointer bp = memory.getPointer(offset);
|
||||
if (bp == null) {
|
||||
result = null;
|
||||
}
|
||||
else {
|
||||
Pointer oldbp = currentValue == null ? null
|
||||
: Native.getDirectBufferPointer((Buffer)currentValue);
|
||||
if (oldbp == null || !oldbp.equals(bp)) {
|
||||
throw new IllegalStateException("Can't autogenerate a direct buffers on Structure read");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (nativeType.isArray()) {
|
||||
result = currentValue;
|
||||
if (result == null) {
|
||||
throw new IllegalStateException("Array field in Structure not initialized");
|
||||
}
|
||||
readArrayValue(offset, result, nativeType.getComponentType());
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Unsupported field type \""
|
||||
+ nativeType + "\"");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private void readArrayValue(int offset, Object o, Class cls) {
|
||||
int length = 0;
|
||||
length = Array.getLength(o);
|
||||
Object result = o;
|
||||
|
||||
if (cls == byte.class) {
|
||||
memory.read(offset, (byte[])result, 0, length);
|
||||
}
|
||||
else if (cls == short.class) {
|
||||
memory.read(offset, (short[])result, 0, length);
|
||||
}
|
||||
else if (cls == char.class) {
|
||||
memory.read(offset, (char[])result, 0, length);
|
||||
}
|
||||
else if (cls == int.class) {
|
||||
memory.read(offset, (int[])result, 0, length);
|
||||
}
|
||||
else if (cls == long.class) {
|
||||
memory.read(offset, (long[])result, 0, length);
|
||||
}
|
||||
else if (cls == float.class) {
|
||||
memory.read(offset, (float[])result, 0, length);
|
||||
}
|
||||
else if (cls == double.class) {
|
||||
memory.read(offset, (double[])result, 0, length);
|
||||
}
|
||||
else if (Pointer.class.isAssignableFrom(cls)) {
|
||||
memory.read(offset, (Pointer[])result, 0, length);
|
||||
}
|
||||
else if (Structure.class.isAssignableFrom(cls)) {
|
||||
Structure[] sarray = (Structure[])result;
|
||||
if (ByReference.class.isAssignableFrom(cls)) {
|
||||
Pointer[] parray = memory.getPointerArray(offset, sarray.length);
|
||||
for (int i=0;i < sarray.length;i++) {
|
||||
sarray[i] = updateStructureByReference(cls, sarray[i], parray[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i=0;i < sarray.length;i++) {
|
||||
if (sarray[i] == null) {
|
||||
sarray[i] = newInstance(cls);
|
||||
}
|
||||
sarray[i].useMemory(memory, offset + i * sarray[i].size());
|
||||
sarray[i].read();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (NativeMapped.class.isAssignableFrom(cls)) {
|
||||
NativeMapped[] array = (NativeMapped[])result;
|
||||
NativeMappedConverter tc = NativeMappedConverter.getInstance(cls);
|
||||
int size = getNativeSize(result.getClass(), result) / array.length;
|
||||
for (int i=0;i < array.length;i++) {
|
||||
// FIXME: use proper context
|
||||
Object value = readValue(offset + size*i, tc.nativeType(), array[i]);
|
||||
array[i] = (NativeMapped)tc.fromNative(value, new FromNativeContext(cls));
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Array of "
|
||||
+ cls + " not supported");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the fields of the struct to native memory
|
||||
*/
|
||||
@@ -589,11 +451,10 @@ public abstract class Structure {
|
||||
getTypeInfo();
|
||||
}
|
||||
|
||||
synchronized(writing) {
|
||||
if (writing.contains(this))
|
||||
return;
|
||||
writing.add(this);
|
||||
if (busy().contains(this)) {
|
||||
return;
|
||||
}
|
||||
busy().add(this);
|
||||
try {
|
||||
// Write all fields, except those marked 'volatile'
|
||||
for (Iterator i=structFields.values().iterator();i.hasNext();) {
|
||||
@@ -604,9 +465,7 @@ public abstract class Structure {
|
||||
}
|
||||
}
|
||||
finally {
|
||||
synchronized(writing) {
|
||||
writing.remove(this);
|
||||
}
|
||||
busy().remove(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -644,19 +503,19 @@ public abstract class Structure {
|
||||
Object value = getField(structField);
|
||||
|
||||
// Determine the type of the field
|
||||
Class nativeType = structField.type;
|
||||
Class fieldType = structField.type;
|
||||
ToNativeConverter converter = structField.writeConverter;
|
||||
if (converter != null) {
|
||||
value = converter.toNative(value, new StructureWriteContext(this, structField.field));
|
||||
nativeType = converter.nativeType();
|
||||
fieldType = converter.nativeType();
|
||||
}
|
||||
|
||||
// Java strings get converted to C strings, where a Pointer is used
|
||||
if (String.class == nativeType
|
||||
|| WString.class == nativeType) {
|
||||
if (String.class == fieldType
|
||||
|| WString.class == fieldType) {
|
||||
|
||||
// Allocate a new string in memory
|
||||
boolean wide = nativeType == WString.class;
|
||||
boolean wide = fieldType == WString.class;
|
||||
if (value != null) {
|
||||
NativeString nativeString = new NativeString(value.toString(), wide);
|
||||
// Keep track of allocated C strings to avoid
|
||||
@@ -670,153 +529,20 @@ public abstract class Structure {
|
||||
}
|
||||
}
|
||||
|
||||
if (!writeValue(offset, value, nativeType)) {
|
||||
try {
|
||||
memory.setValue(offset, value, fieldType);
|
||||
}
|
||||
catch(IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
String msg = "Structure field \"" + structField.name
|
||||
+ "\" was declared as " + structField.type
|
||||
+ (structField.type == nativeType ? "" : " (native type " + nativeType + ")")
|
||||
+ (structField.type == fieldType
|
||||
? "" : " (native type " + fieldType + ")")
|
||||
+ ", which is not supported within a Structure";
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean writeValue(int offset, Object value, Class nativeType) {
|
||||
|
||||
// Set the value at the offset according to its type
|
||||
if (nativeType == boolean.class || nativeType == Boolean.class) {
|
||||
memory.setInt(offset, Boolean.TRUE.equals(value) ? -1 : 0);
|
||||
}
|
||||
else if (nativeType == byte.class || nativeType == Byte.class) {
|
||||
memory.setByte(offset, value == null ? 0 : ((Byte)value).byteValue());
|
||||
}
|
||||
else if (nativeType == short.class || nativeType == Short.class) {
|
||||
memory.setShort(offset, value == null ? 0 : ((Short)value).shortValue());
|
||||
}
|
||||
else if (nativeType == char.class || nativeType == Character.class) {
|
||||
memory.setChar(offset, value == null ? 0 : ((Character)value).charValue());
|
||||
}
|
||||
else if (nativeType == int.class || nativeType == Integer.class) {
|
||||
memory.setInt(offset, value == null ? 0 : ((Integer)value).intValue());
|
||||
}
|
||||
else if (nativeType == long.class || nativeType == Long.class) {
|
||||
memory.setLong(offset, value == null ? 0 : ((Long)value).longValue());
|
||||
}
|
||||
else if (nativeType == float.class || nativeType == Float.class) {
|
||||
memory.setFloat(offset, value == null ? 0f : ((Float)value).floatValue());
|
||||
}
|
||||
else if (nativeType == double.class || nativeType == Double.class) {
|
||||
memory.setDouble(offset, value == null ? 0.0 : ((Double)value).doubleValue());
|
||||
}
|
||||
else if (nativeType == Pointer.class) {
|
||||
memory.setPointer(offset, (Pointer)value);
|
||||
}
|
||||
else if (nativeType == String.class) {
|
||||
memory.setPointer(offset, (Pointer)value);
|
||||
}
|
||||
else if (nativeType == WString.class) {
|
||||
memory.setPointer(offset, (Pointer)value);
|
||||
}
|
||||
else if (Structure.class.isAssignableFrom(nativeType)) {
|
||||
Structure s = (Structure)value;
|
||||
if (ByReference.class.isAssignableFrom(nativeType)) {
|
||||
memory.setPointer(offset, s == null ? null : s.getPointer());
|
||||
if (s != null) {
|
||||
s.write();
|
||||
}
|
||||
}
|
||||
else {
|
||||
s.useMemory(memory, offset);
|
||||
s.write();
|
||||
}
|
||||
}
|
||||
else if (Callback.class.isAssignableFrom(nativeType)) {
|
||||
memory.setPointer(offset, CallbackReference.getFunctionPointer((Callback)value));
|
||||
}
|
||||
else if (nativeType == Buffer.class) {
|
||||
Pointer p = value == null ? null
|
||||
: Native.getDirectBufferPointer((Buffer)value);
|
||||
memory.setPointer(offset, p);
|
||||
}
|
||||
else if (nativeType.isArray()) {
|
||||
return writeArrayValue(offset, value, nativeType.getComponentType());
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean writeArrayValue(int offset, Object value, Class cls) {
|
||||
if (cls == byte.class) {
|
||||
byte[] buf = (byte[])value;
|
||||
memory.write(offset, buf, 0, buf.length);
|
||||
}
|
||||
else if (cls == short.class) {
|
||||
short[] buf = (short[])value;
|
||||
memory.write(offset, buf, 0, buf.length);
|
||||
}
|
||||
else if (cls == char.class) {
|
||||
char[] buf = (char[])value;
|
||||
memory.write(offset, buf, 0, buf.length);
|
||||
}
|
||||
else if (cls == int.class) {
|
||||
int[] buf = (int[])value;
|
||||
memory.write(offset, buf, 0, buf.length);
|
||||
}
|
||||
else if (cls == long.class) {
|
||||
long[] buf = (long[])value;
|
||||
memory.write(offset, buf, 0, buf.length);
|
||||
}
|
||||
else if (cls == float.class) {
|
||||
float[] buf = (float[])value;
|
||||
memory.write(offset, buf, 0, buf.length);
|
||||
}
|
||||
else if (cls == double.class) {
|
||||
double[] buf = (double[])value;
|
||||
memory.write(offset, buf, 0, buf.length);
|
||||
}
|
||||
else if (Pointer.class.isAssignableFrom(cls)) {
|
||||
Pointer[] buf = (Pointer[])value;
|
||||
memory.write(offset, buf, 0, buf.length);
|
||||
}
|
||||
else if (Structure.class.isAssignableFrom(cls)) {
|
||||
Structure[] sbuf = (Structure[])value;
|
||||
if (ByReference.class.isAssignableFrom(cls)) {
|
||||
Pointer[] buf = new Pointer[sbuf.length];
|
||||
for (int i=0;i < sbuf.length;i++) {
|
||||
buf[i] = sbuf[i] == null ? null : sbuf[i].getPointer();
|
||||
}
|
||||
memory.write(offset, buf, 0, buf.length);
|
||||
}
|
||||
else {
|
||||
for (int i=0;i < sbuf.length;i++) {
|
||||
if (sbuf[i] == null) {
|
||||
sbuf[i] = newInstance(cls);
|
||||
}
|
||||
sbuf[i].useMemory(memory, offset + i * sbuf[i].size());
|
||||
sbuf[i].write();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (NativeMapped.class.isAssignableFrom(cls)) {
|
||||
NativeMapped[] buf = (NativeMapped[])value;
|
||||
NativeMappedConverter tc = NativeMappedConverter.getInstance(cls);
|
||||
Class nativeType = tc.nativeType();
|
||||
int size = getNativeSize(value.getClass(), value) / buf.length;
|
||||
for (int i=0;i < buf.length;i++) {
|
||||
// FIXME: incorrect context
|
||||
Object element = tc.toNative(buf[i], new ToNativeContext());
|
||||
if (!writeValue(offset + i*size, element, nativeType)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Inline array of "
|
||||
+ cls + " not supported");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected List getFieldOrder() {
|
||||
synchronized(this) {
|
||||
if (fieldOrder == null) {
|
||||
@@ -978,7 +704,7 @@ public abstract class Structure {
|
||||
}
|
||||
}
|
||||
try {
|
||||
structField.size = getNativeSize(nativeType, value);
|
||||
structField.size = Native.getNativeSize(nativeType, value);
|
||||
fieldAlignment = getNativeAlignment(nativeType, value, i==0);
|
||||
}
|
||||
catch(IllegalArgumentException e) {
|
||||
@@ -986,7 +712,8 @@ public abstract class Structure {
|
||||
if (!force && typeMapper == null) {
|
||||
return CALCULATE_SIZE;
|
||||
}
|
||||
throw e;
|
||||
String msg = "Invalid Structure field in " + getClass() + ", field name '" + structField.name + "', " + structField.type + ": " + e.getMessage();
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
|
||||
// Align fields as appropriate
|
||||
@@ -1045,7 +772,7 @@ public abstract class Structure {
|
||||
type = tc.nativeType();
|
||||
value = tc.toNative(value, new ToNativeContext());
|
||||
}
|
||||
int size = getNativeSize(type, value);
|
||||
int size = Native.getNativeSize(type, value);
|
||||
if (type.isPrimitive() || Long.class == type || Integer.class == type
|
||||
|| Short.class == type || Character.class == type
|
||||
|| Byte.class == type || Boolean.class == type
|
||||
@@ -1092,33 +819,6 @@ public abstract class Structure {
|
||||
return alignment;
|
||||
}
|
||||
|
||||
/** Returns the native size of the given class, in bytes. */
|
||||
private static int getNativeSize(Class type, Object value) {
|
||||
if (type.isArray()) {
|
||||
int len = Array.getLength(value);
|
||||
if (len > 0) {
|
||||
Object o = Array.get(value, 0);
|
||||
return len * getNativeSize(type.getComponentType(), o);
|
||||
}
|
||||
// Don't process zero-length arrays
|
||||
throw new IllegalArgumentException("Arrays of length zero not allowed in structure: " + type);
|
||||
}
|
||||
if (Structure.class.isAssignableFrom(type)
|
||||
&& !Structure.ByReference.class.isAssignableFrom(type)) {
|
||||
if (value == null)
|
||||
value = newInstance(type);
|
||||
return ((Structure)value).size();
|
||||
}
|
||||
try {
|
||||
return Native.getNativeSize(type);
|
||||
}
|
||||
catch(IllegalArgumentException e) {
|
||||
throw new IllegalArgumentException("The type \"" + type.getName()
|
||||
+ "\" is not supported as a structure field: "
|
||||
+ e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return toString(0);
|
||||
}
|
||||
@@ -1165,7 +865,22 @@ public abstract class Structure {
|
||||
value = ((Structure)value).toString(indent + 1);
|
||||
}
|
||||
}
|
||||
contents += "=" + String.valueOf(value).trim();
|
||||
contents += "=";
|
||||
if (value instanceof Long) {
|
||||
contents += Long.toHexString(((Long)value).longValue());
|
||||
}
|
||||
else if (value instanceof Integer) {
|
||||
contents += Integer.toHexString(((Integer)value).intValue());
|
||||
}
|
||||
else if (value instanceof Short) {
|
||||
contents += Integer.toHexString(((Short)value).shortValue());
|
||||
}
|
||||
else if (value instanceof Byte) {
|
||||
contents += Integer.toHexString(((Byte)value).byteValue());
|
||||
}
|
||||
else {
|
||||
contents += String.valueOf(value).trim();
|
||||
}
|
||||
contents += LS;
|
||||
if (!i.hasNext())
|
||||
contents += prefix + "}";
|
||||
@@ -1211,6 +926,11 @@ public abstract class Structure {
|
||||
array[i].useMemory(memory.share(i*size, size));
|
||||
array[i].read();
|
||||
}
|
||||
|
||||
if (this instanceof ByReference) {
|
||||
this.array = array;
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
@@ -1229,20 +949,35 @@ public abstract class Structure {
|
||||
public boolean equals(Object o) {
|
||||
if (o == this)
|
||||
return true;
|
||||
if (o instanceof Structure && ((Structure)o).size() == size()) {
|
||||
if (o.getClass().isAssignableFrom(getClass())
|
||||
|| getClass().isAssignableFrom(o.getClass())) {
|
||||
Structure s = (Structure)o;
|
||||
Pointer p1 = getPointer();
|
||||
Pointer p2 = s.getPointer();
|
||||
for (int i=0;i < size();i++) {
|
||||
if (p1.getByte(i) != p2.getByte(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
if (o == null)
|
||||
return false;
|
||||
if (o.getClass() != getClass()) {
|
||||
// Only allow one class derived from the other and implementing
|
||||
// ByReference or ByValue, or both implementing
|
||||
// ByReference/ByValue on the same base class
|
||||
if (!((o.getClass().isAssignableFrom(getClass())
|
||||
&& (ByReference.class.isAssignableFrom(getClass())
|
||||
|| ByValue.class.isAssignableFrom(getClass())))
|
||||
|| (getClass().isAssignableFrom(o.getClass())
|
||||
&& (ByReference.class.isAssignableFrom(o.getClass())
|
||||
|| ByValue.class.isAssignableFrom(o.getClass())))
|
||||
|| ((ByReference.class.isAssignableFrom(o.getClass())
|
||||
|| ByValue.class.isAssignableFrom(o.getClass()))
|
||||
&& (ByReference.class.isAssignableFrom(getClass())
|
||||
|| ByValue.class.isAssignableFrom(getClass()))
|
||||
&& (o.getClass().getSuperclass()
|
||||
== getClass().getSuperclass())))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Structure s = (Structure)o;
|
||||
if (s.size() == size()) {
|
||||
clear(); write();
|
||||
byte[] buf = getPointer().getByteArray(0, size());
|
||||
s.clear(); s.write();
|
||||
byte[] sbuf = s.getPointer().getByteArray(0, s.size());
|
||||
return Arrays.equals(buf, sbuf);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1250,8 +985,8 @@ public abstract class Structure {
|
||||
* as the hash code.
|
||||
*/
|
||||
public int hashCode() {
|
||||
Pointer p = getPointer();
|
||||
return p != null ? p.hashCode() : 0;
|
||||
clear(); write();
|
||||
return Arrays.hashCode(getPointer().getByteArray(0, size()));
|
||||
}
|
||||
|
||||
protected void cacheTypeInfo(Pointer p) {
|
||||
@@ -1397,6 +1132,8 @@ public abstract class Structure {
|
||||
typeInfoMap.put(Character.class, ctype);
|
||||
typeInfoMap.put(byte.class, FFITypes.ffi_type_sint8);
|
||||
typeInfoMap.put(Byte.class, FFITypes.ffi_type_sint8);
|
||||
typeInfoMap.put(boolean.class, FFITypes.ffi_type_uint32);
|
||||
typeInfoMap.put(Boolean.class, FFITypes.ffi_type_uint32);
|
||||
typeInfoMap.put(Pointer.class, FFITypes.ffi_type_pointer);
|
||||
typeInfoMap.put(String.class, FFITypes.ffi_type_pointer);
|
||||
typeInfoMap.put(WString.class, FFITypes.ffi_type_pointer);
|
||||
@@ -1485,22 +1222,9 @@ public abstract class Structure {
|
||||
typeInfoMap.put(obj, type);
|
||||
return type.getPointer();
|
||||
}
|
||||
throw new IllegalArgumentException("Unsupported structure field type " + cls);
|
||||
throw new IllegalArgumentException("Unsupported type " + cls);
|
||||
}
|
||||
}
|
||||
static String getSignature(Object o) {
|
||||
Pointer p = get(o);
|
||||
if (p == FFITypes.ffi_type_void) return "V";
|
||||
if (p == FFITypes.ffi_type_float) return "F";
|
||||
if (p == FFITypes.ffi_type_double) return "D";
|
||||
if (p == FFITypes.ffi_type_sint8) return "B";
|
||||
if (p == FFITypes.ffi_type_sint16) return "S";
|
||||
if (p == FFITypes.ffi_type_uint16) return "C";
|
||||
if (p == FFITypes.ffi_type_sint32) return "I";
|
||||
if (p == FFITypes.ffi_type_sint64) return "J";
|
||||
if (p == FFITypes.ffi_type_pointer) return "Lcom/sun/jna/Pointer;";
|
||||
throw new IllegalArgumentException("Unsupported type " + o);
|
||||
}
|
||||
}
|
||||
|
||||
private class AutoAllocated extends Memory {
|
||||
@@ -1508,4 +1232,26 @@ public abstract class Structure {
|
||||
super(size);
|
||||
}
|
||||
}
|
||||
|
||||
public void autoRead() {
|
||||
if (getAutoRead()) {
|
||||
read();
|
||||
if (array != null) {
|
||||
for (int i=1;i < array.length;i++) {
|
||||
array[i].autoRead();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void autoWrite() {
|
||||
if (getAutoWrite()) {
|
||||
write();
|
||||
if (array != null) {
|
||||
for (int i=1;i < array.length;i++) {
|
||||
array[i].autoWrite();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.nio.CharBuffer;
|
||||
public final class WString implements CharSequence, Comparable {
|
||||
private String string;
|
||||
public WString(String s){
|
||||
if (s == null) throw new NullPointerException("String initializer must be non-null");
|
||||
this.string = s;
|
||||
}
|
||||
public String toString() {
|
||||
|
||||
@@ -275,6 +275,7 @@ public interface X11 extends Library {
|
||||
|
||||
/** Definition of the Xevie library. */
|
||||
interface Xevie extends Library {
|
||||
/** Instance of Xevie. Note: This extension has been removed from xorg/xserver on Oct 22, 2008 because it is broken and maintainerless. */
|
||||
Xevie INSTANCE = (Xevie)Native.loadLibrary("Xevie", Xevie.class);
|
||||
int XEVIE_UNMODIFIED = 0;
|
||||
int XEVIE_MODIFIED = 1;
|
||||
|
||||
@@ -65,4 +65,65 @@ public interface Shell32 extends W32API {
|
||||
}
|
||||
}
|
||||
int SHFileOperation(SHFILEOPSTRUCT fileop);
|
||||
|
||||
DWORD SHGFP_TYPE_CURRENT = new DWORD(0); // current value for user, verify it exists
|
||||
DWORD SHGFP_TYPE_DEFAULT = new DWORD(1); // default value, may not exist
|
||||
int CSIDL_DESKTOP = 0x0000; // <desktop>
|
||||
int CSIDL_INTERNET = 0x0001; // Internet Explorer (icon on desktop)
|
||||
int CSIDL_PROGRAMS = 0x0002; // Start Menu\Programs
|
||||
int CSIDL_CONTROLS = 0x0003; // My Computer\Control Panel
|
||||
int CSIDL_PRINTERS = 0x0004; // My Computer\Printers
|
||||
int CSIDL_PERSONAL = 0x0005; // My Documents
|
||||
int CSIDL_FAVORITES = 0x0006; // <user name>\Favorites
|
||||
int CSIDL_STARTUP = 0x0007; // Start Menu\Programs\Startup
|
||||
int CSIDL_RECENT = 0x0008; // <user name>\Recent
|
||||
int CSIDL_SENDTO = 0x0009; // <user name>\SendTo
|
||||
int CSIDL_BITBUCKET = 0x000a; // <desktop>\Recycle Bin
|
||||
int CSIDL_STARTMENU = 0x000b; // <user name>\Start Menu
|
||||
int CSIDL_MYDOCUMENTS = CSIDL_PERSONAL; // Personal was just a silly name for My Documents
|
||||
int CSIDL_MYMUSIC = 0x000d; // "My Music" folder
|
||||
int CSIDL_MYVIDEO = 0x000e; // "My Videos" folder
|
||||
int CSIDL_DESKTOPDIRECTORY = 0x0010; // <user name>\Desktop
|
||||
int CSIDL_DRIVES = 0x0011; // My Computer
|
||||
int CSIDL_NETWORK = 0x0012; // Network Neighborhood (My Network Places)
|
||||
int CSIDL_NETHOOD = 0x0013; // <user name>\nethood
|
||||
int CSIDL_FONTS = 0x0014; // windows\fonts
|
||||
int CSIDL_TEMPLATES = 0x0015;
|
||||
int CSIDL_COMMON_STARTMENU = 0x0016; // All Users\Start Menu
|
||||
int CSIDL_COMMON_PROGRAMS = 0X0017; // All Users\Start Menu\Programs
|
||||
int CSIDL_COMMON_STARTUP = 0x0018; // All Users\Startup
|
||||
int CSIDL_COMMON_DESKTOPDIRECTORY = 0x0019; // All Users\Desktop
|
||||
int CSIDL_APPDATA = 0x001a; // <user name>\Application Data
|
||||
int CSIDL_PRINTHOOD = 0x001b; // <user name>\PrintHood
|
||||
int CSIDL_LOCAL_APPDATA = 0x001c; // <user name>\Local Settings\Applicaiton Data (non roaming)
|
||||
int CSIDL_ALTSTARTUP = 0x001d; // non localized startup
|
||||
int CSIDL_COMMON_ALTSTARTUP = 0x001e; // non localized common startup
|
||||
int CSIDL_COMMON_FAVORITES = 0x001f;
|
||||
int CSIDL_INTERNET_CACHE = 0x0020;
|
||||
int CSIDL_COOKIES = 0x0021;
|
||||
int CSIDL_HISTORY = 0x0022;
|
||||
int CSIDL_COMMON_APPDATA = 0x0023; // All Users\Application Data
|
||||
int CSIDL_WINDOWS = 0x0024; // GetWindowsDirectory()
|
||||
int CSIDL_SYSTEM = 0x0025; // GetSystemDirectory()
|
||||
int CSIDL_PROGRAM_FILES = 0x0026; // C:\Program Files
|
||||
int CSIDL_MYPICTURES = 0x0027; // C:\Program Files\My Pictures
|
||||
int CSIDL_PROFILE = 0x0028; // USERPROFILE
|
||||
int CSIDL_SYSTEMX86 = 0x0029; // x86 system directory on RISC
|
||||
int CSIDL_PROGRAM_FILESX86 = 0x002a; // x86 C:\Program Files on RISC
|
||||
int CSIDL_PROGRAM_FILES_COMMON = 0x002b; // C:\Program Files\Common
|
||||
int CSIDL_PROGRAM_FILES_COMMONX86 = 0x002c; // x86 Program Files\Common on RISC
|
||||
int CSIDL_COMMON_TEMPLATES = 0x002d; // All Users\Templates
|
||||
int CSIDL_COMMON_DOCUMENTS = 0x002e; // All Users\Documents
|
||||
int CSIDL_COMMON_ADMINTOOLS = 0x002f; // All Users\Start Menu\Programs\Administrative Tools
|
||||
int CSIDL_ADMINTOOLS = 0x0030; // <user name>\Start Menu\Programs\Administrative Tools
|
||||
int CSIDL_CONNECTIONS = 0x0031; // Network and Dial-up Connections
|
||||
int CSIDL_COMMON_MUSIC = 0x0035; // All Users\My Music
|
||||
int CSIDL_COMMON_PICTURES = 0x0036; // All Users\My Pictures
|
||||
int CSIDL_COMMON_VIDEO = 0x0037; // All Users\My Video
|
||||
int CSIDL_RESOURCES = 0x0038; // Resource Direcotry
|
||||
int CSIDL_RESOURCES_LOCALIZED = 0x0039; // Localized Resource Direcotry
|
||||
int CSIDL_COMMON_OEM_LINKS = 0x003a; // Links to All Users OEM specific apps
|
||||
int CSIDL_CDBURN_AREA = 0x003b; // USERPROFILE\Local Settings\Application Data\Microsoft\CD Burning
|
||||
int CSIDL_COMPUTERSNEARME = 0x003d; // Computers Near Me (computered from Workgroup membership)
|
||||
HRESULT SHGetFolderPath(HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwFlags, char[] pszPath);
|
||||
}
|
||||
|
||||
@@ -68,7 +68,10 @@ public interface User32 extends W32API {
|
||||
int LR_SHARED =0x8000;
|
||||
|
||||
HWND FindWindow(String winClass, String title);
|
||||
/** ASCII version. */
|
||||
int GetClassName(HWND hWnd, byte[] lpClassName, int nMaxCount);
|
||||
/** Unicode version. */
|
||||
int GetClassName(HWND hWnd, char[] lpClassName, int nMaxCount);
|
||||
class GUITHREADINFO extends Structure {
|
||||
public int cbSize = size();
|
||||
public int flags;
|
||||
@@ -96,15 +99,22 @@ public interface User32 extends W32API {
|
||||
}
|
||||
boolean GetWindowInfo(HWND hWnd, WINDOWINFO pwi);
|
||||
boolean GetWindowRect(HWND hWnd, RECT rect);
|
||||
/** ASCII version. */
|
||||
int GetWindowText(HWND hWnd, byte[] lpString, int nMaxCount);
|
||||
/** Unicode version. */
|
||||
int GetWindowText(HWND hWnd, char[] lpString, int nMaxCount);
|
||||
int GetWindowTextLength(HWND hWnd);
|
||||
/** ASCII version. */
|
||||
int GetWindowModuleFileName(HWND hWnd, byte[] lpszFileName, int cchFileNameMax);
|
||||
/** Unicode version. */
|
||||
int GetWindowModuleFileName(HWND hWnd, char[] lpszFileName, int cchFileNameMax);
|
||||
int GetWindowThreadProcessId(HWND hWnd, IntByReference lpdwProcessId);
|
||||
interface WNDENUMPROC extends StdCallCallback {
|
||||
/** Return whether to continue enumeration. */
|
||||
boolean callback(HWND hWnd, Pointer data);
|
||||
}
|
||||
boolean EnumWindows(WNDENUMPROC lpEnumFunc, Pointer data);
|
||||
boolean EnumChildWindows(HWND hWnd, WNDENUMPROC lpEnumFunc, Pointer data);
|
||||
boolean EnumThreadWindows(int dwThreadId, WNDENUMPROC lpEnumFunc, Pointer data);
|
||||
|
||||
boolean FlashWindowEx(FLASHWINFO info);
|
||||
|
||||
@@ -17,6 +17,8 @@ import java.util.Map;
|
||||
|
||||
import com.sun.jna.FromNativeContext;
|
||||
import com.sun.jna.IntegerType;
|
||||
import com.sun.jna.Native;
|
||||
import com.sun.jna.NativeLong;
|
||||
import com.sun.jna.Pointer;
|
||||
import com.sun.jna.PointerType;
|
||||
import com.sun.jna.ptr.ByReference;
|
||||
@@ -47,6 +49,9 @@ public interface W32API extends StdCallLibrary, W32Errors {
|
||||
Map DEFAULT_OPTIONS = Boolean.getBoolean("w32.ascii") ? ASCII_OPTIONS : UNICODE_OPTIONS;
|
||||
|
||||
class HANDLE extends PointerType {
|
||||
private boolean immutable;
|
||||
public HANDLE() { }
|
||||
public HANDLE(Pointer p) { setPointer(p); immutable = true; }
|
||||
/** Override to the appropriate object for INVALID_HANDLE_VALUE. */
|
||||
public Object fromNative(Object nativeValue, FromNativeContext context) {
|
||||
Object o = super.fromNative(nativeValue, context);
|
||||
@@ -54,6 +59,11 @@ public interface W32API extends StdCallLibrary, W32Errors {
|
||||
return INVALID_HANDLE_VALUE;
|
||||
return o;
|
||||
}
|
||||
public void setPointer(Pointer p) {
|
||||
if (immutable)
|
||||
throw new UnsupportedOperationException("immutable reference");
|
||||
super.setPointer(p);
|
||||
}
|
||||
}
|
||||
|
||||
class WORD extends IntegerType {
|
||||
@@ -64,29 +74,29 @@ public interface W32API extends StdCallLibrary, W32Errors {
|
||||
public DWORD() { this(0); }
|
||||
public DWORD(long value) { super(4, value); }
|
||||
}
|
||||
class LONG extends IntegerType {
|
||||
public LONG() { this(0); }
|
||||
public LONG(long value) { super(Native.LONG_SIZE, value); }
|
||||
}
|
||||
|
||||
class HDC extends HANDLE { }
|
||||
class HICON extends HANDLE { }
|
||||
class HBITMAP extends HANDLE { }
|
||||
class HRGN extends HANDLE { }
|
||||
class HWND extends HANDLE { }
|
||||
class HWND extends HANDLE {
|
||||
public HWND() { }
|
||||
public HWND(Pointer p) { super(p); }
|
||||
}
|
||||
class HINSTANCE extends HANDLE { }
|
||||
class HMODULE extends HINSTANCE { }
|
||||
class HRESULT extends NativeLong { }
|
||||
|
||||
/** Constant value representing an invalid HANDLE. */
|
||||
HANDLE INVALID_HANDLE_VALUE = new HANDLE() {
|
||||
{ super.setPointer(Pointer.createConstant(-1)); }
|
||||
public void setPointer(Pointer p) {
|
||||
throw new UnsupportedOperationException("Immutable reference");
|
||||
}
|
||||
};
|
||||
HANDLE INVALID_HANDLE_VALUE = new HANDLE(Pointer.createConstant(-1));
|
||||
|
||||
/** Special HWND value. */
|
||||
HWND HWND_BROADCAST = new HWND() {
|
||||
{ super.setPointer(Pointer.createConstant(0xFFFF)); }
|
||||
public void setPointer(Pointer p) {
|
||||
throw new UnsupportedOperationException("Immutable reference");
|
||||
}
|
||||
};
|
||||
HWND HWND_BROADCAST = new HWND(Pointer.createConstant(0xFFFF));
|
||||
|
||||
/** LPHANDLE */
|
||||
class HANDLEByReference extends ByReference {
|
||||
public HANDLEByReference() {
|
||||
|
||||
@@ -44,6 +44,7 @@ additional JNI or native code.
|
||||
<li><a href="#structures">Structures</a>
|
||||
<li><a href="#unions">Unions</a>
|
||||
<li><a href="#java-objects">Java Objects</a>
|
||||
<li><a href="#last-error">Last Error</a>
|
||||
</ul>
|
||||
<li><a href="#invocation-mapping">Invocation Mapping</a>
|
||||
<li><a href="#global-data">Library Global Data</a>
|
||||
@@ -56,14 +57,25 @@ additional JNI or native code.
|
||||
<a name="library-mapping"></a>
|
||||
<h2>Library Mapping</h2>
|
||||
When you've determined which shared library holds the methods to which you
|
||||
need access, create an interface class corresponding to that library. For
|
||||
example, a mapping for the C library itself would look like this:<br>
|
||||
need access, create a class corresponding to that library. For
|
||||
example, a mapping for the C library itself would look like one of the
|
||||
following:<br>
|
||||
<blockquote><code><pre>
|
||||
// Alternative 1: interface-mapped class, dynamically load the C library
|
||||
public interface CLibrary extends Library {
|
||||
CLibrary INSTANCE = (CLibrary)Native.loadLibrary("c", CLibrary.class);
|
||||
}
|
||||
|
||||
// Alternative 2: direct-mapped class
|
||||
public class CLibrary {
|
||||
static {
|
||||
Native.register("c");
|
||||
}
|
||||
}
|
||||
</pre></code></blockquote>
|
||||
The <code>String</code> passed to the <code>Native.loadLibrary</code> method
|
||||
The <code>String</code> passed to the
|
||||
{@link com.sun.jna.Native#loadLibrary(String,Class)}
|
||||
(or {@link com.sun.jna.NativeLibrary#getInstance(String)}) method
|
||||
is the undecorated name of the shared library file. Here are some examples of
|
||||
library name mappings.<p>
|
||||
<style type="text/css">
|
||||
@@ -77,11 +89,18 @@ blockquote { background-color:#EAEAEA; }
|
||||
<tr><td>Linux</td><td>libX11.so</td><td>X11</td></tr>
|
||||
<tr><td>Mac OS X</td><td>libm.dylib</td><td>m</td></tr>
|
||||
<tr><td>Mac OS X Framework</td><td>/System/Library/Frameworks/Carbon.framework/Carbon</td><td>Carbon</td></tr>
|
||||
<tr><td>Any Platform</td><td><current process></td><td><code>null</code></td></tr>
|
||||
</table>
|
||||
<p>
|
||||
Any given native library with a unique filesystem path is represented by a single instance of {@link com.sun.jna.NativeLibrary} and obtained via {@link com.sun.jna.NativeLibrary#getInstance(String)}. The native library will be unloaded when no longer referenced by any Java code.
|
||||
<p>
|
||||
The search path for loaded native libraries may be modified by setting <code>jna.library.path</code>. See {@link com.sun.jna.NativeLibrary} for details.
|
||||
If the library name is <code>null</code>, your mappings will apply to the
|
||||
current process instead of a separately loaded library. This may help avoid
|
||||
conflicts if there are several incompatible versions of a library available.
|
||||
<p>
|
||||
The search path for loaded native libraries may be modified by
|
||||
setting <code>jna.library.path</code> and a few other properties. See {@link
|
||||
com.sun.jna.NativeLibrary} for details.
|
||||
<p>
|
||||
<a href="#toc">Table of Contents</a>
|
||||
<a name="function-mapping"></a>
|
||||
@@ -94,6 +113,13 @@ public interface CLibrary extends Library {
|
||||
int atol(String s);
|
||||
}
|
||||
</pre></code></blockquote>
|
||||
Alternatively, you can map directly to a declared native method:<br>
|
||||
<blockquote><code><pre>
|
||||
public class CLibrary {
|
||||
public static native int atol(String s);
|
||||
}
|
||||
</pre></code></blockquote>
|
||||
|
||||
If you prefer to rename the Java methods to conform to Java coding conventions, then you can provide an entry ({@link com.sun.jna.Library#OPTION_FUNCTION_MAPPER}/{@link com.sun.jna.FunctionMapper}) in the options {@link java.util.Map} passed to {@link com.sun.jna.Native#loadLibrary(String,Class,java.util.Map) Native.loadLibrary()} which maps the Java names to the native names. While this keeps your Java code a little cleaner, the additional mapping of names may make it a little less obvious the native functions being called.<p>
|
||||
An instance of the {@link com.sun.jna.Function} class is obtained through the {@link com.sun.jna.NativeLibrary} instance corresponding to the containing native library. This {@link com.sun.jna.Function} instance handles argument marshalling and delegation to the native function.
|
||||
|
||||
@@ -106,30 +132,33 @@ An instance of the {@link com.sun.jna.Function} class is obtained through the {@
|
||||
Java types must be chosen to match native types of the same size. Following are the types supported by the JNA library.<p>
|
||||
<center>
|
||||
<table border=1 borderColor=white class=styled width="100%">
|
||||
<tr><td><b>Java Type</b></td><td><b>C Type</b></td><td><b>Native Representation</b></td></tr>
|
||||
<tr><td>boolean</td><td>int</td><td>32-bit integer (customizable)</td>
|
||||
<tr><td>byte</td><td>char</td><td>8-bit integer</td>
|
||||
<tr><td>char</td><td>wchar_t</td><td>platform-dependent</td>
|
||||
<tr><td>short</td><td>short</td><td>16-bit integer</td>
|
||||
<tr><td>int</td><td>int</td><td>32-bit integer</td>
|
||||
<tr><td>long</td><td>long long, __int64</td><td>64-bit integer</td>
|
||||
<tr><td>float</td><td>float</td><td>32-bit floating point</td>
|
||||
<tr><td>double</td><td>double</td><td>64-bit floating point</td>
|
||||
<tr><td>{@link java.nio.Buffer}<br>
|
||||
{@link com.sun.jna.Pointer}<td>pointer</td><td>platform-dependent (32- or 64-bit pointer to memory)</td>
|
||||
<tr><td><T>[] (array of primitive type)</td><td>pointer<br>array</td><td>32- or 64-bit pointer to memory (argument/return)<br>contiguous memory (struct member)</td>
|
||||
<tr><td colspan=3>In addition to the above types, which are supported at the native layer, the JNA Java library automatically handles the following types. All but <code>NativeMapped</code> and <code>NativeLong</code> are converted to {@link com.sun.jna.Pointer} before being passed to the native layer.</td></tr>
|
||||
<tr><td>{@link java.lang.String}</td><td>char*</td><td>NUL-terminated array (native encoding or <code>jna.encoding</code>)</td>
|
||||
<tr><td>{@link com.sun.jna.WString}</td><td>wchar_t*</td><td>NUL-terminated array (unicode)</td>
|
||||
<tr><td>{@link java.lang.String String[]}</td><td>char**</td><td>NULL-terminated array of C strings</td>
|
||||
<tr><td>{@link com.sun.jna.WString WString[]}</td><td>wchar_t**</td><td>NULL-terminated array of wide C strings</td>
|
||||
<tr><td>{@link com.sun.jna.Structure}</td><td>struct*<br>struct</td><td>pointer to struct (argument or return) ({@link com.sun.jna.Structure.ByReference or explicitly})<br>struct by value (member of struct) ({@link com.sun.jna.Structure.ByValue or explicitly})</td>
|
||||
<tr><td>{@link com.sun.jna.Union}</td><td>union</td><td>same as <code>Structure</code></td>
|
||||
<tr><td>{@link com.sun.jna.Structure Structure[]}</td><td>struct[]</td><td>array of structs, contiguous in memory</td>
|
||||
<tr><td>{@link com.sun.jna.Callback}</td><td><T> (*fp)()</td><td>function pointer (Java or native)</td>
|
||||
<tr><td>{@link com.sun.jna.NativeMapped}</td><td>varies</td><td>depends on definition</td>
|
||||
<tr><td>{@link com.sun.jna.NativeLong}</td><td>long</td><td>platform-dependent (32- or 64-bit integer)</td>
|
||||
<tr><td>{@link com.sun.jna.PointerType}</td><td>pointer</td><td>same as <code>Pointer</code></td>
|
||||
<tr><td><b>C Type</b></td><td><b>Native Representation</b></td><td><b>Java Type</b></td></tr>
|
||||
<tr><td>char</td><td>8-bit integer</td><td>byte</td></tr>
|
||||
<tr><td>wchar_t</td><td>platform-dependent</td><td>char</td></tr>
|
||||
<tr><td>short</td><td>16-bit integer</td><td>short</td></tr>
|
||||
<tr><td>int</td><td>32-bit integer</td><td>int</td></tr>
|
||||
<tr><td>int</td><td>boolean flag</td><td>boolean</td></tr>
|
||||
<tr><td>enum</td><td>enumeration type</td><td>int (usually)</td></tr>
|
||||
<tr><td>long long, __int64</td><td>64-bit integer</td><td>long</td></tr>
|
||||
<tr><td>float</td><td>32-bit floating point</td><td>float</td></tr>
|
||||
<tr><td>double</td><td>64-bit floating point</td><td>double</td></tr>
|
||||
<tr><td>pointer (e.g. void*)</td><td>platform-dependent (32- or 64-bit pointer to memory)</td><td>{@link java.nio.Buffer}<br>
|
||||
{@link com.sun.jna.Pointer}</td></tr>
|
||||
<tr><td>pointer (e.g. void*),<br>array</td><td>32- or 64-bit pointer to memory (argument/return)<br>contiguous memory (struct member)</td><td><P>[] (array of primitive type)</td></tr>
|
||||
<tr><td colspan='3' style='padding:20px 5px'>In addition to the above types, which are supported at the native layer, the JNA Java library automatically handles the following types. All but <code>NativeMapped</code> and <code>NativeLong</code> are converted to {@link com.sun.jna.Pointer} before being passed to the native layer.</td></tr>
|
||||
<tr><td>long</td><td>platform-dependent (32- or 64-bit integer)</td><td>{@link com.sun.jna.NativeLong}</td></tr>
|
||||
<tr><td>const char*</td><td>NUL-terminated array (native encoding or <code>jna.encoding</code>)</td><td>{@link java.lang.String}</td></tr>
|
||||
<tr><td>const wchar_t*</td><td>NUL-terminated array (unicode)</td><td>{@link com.sun.jna.WString}</td></tr>
|
||||
<tr><td>char**</td><td>NULL-terminated array of C strings</td><td>{@link java.lang.String String[]}</td></tr>
|
||||
<tr><td>wchar_t**</td><td>NULL-terminated array of wide C strings</td><td>{@link com.sun.jna.WString WString[]}</td></tr>
|
||||
<tr><td>void**</td><td>NULL-terminated array of pointers</td><td>{@link com.sun.jna.Pointer Pointer[]}</td></tr>
|
||||
<tr><td>struct*<br>struct</td><td>pointer to struct (argument or return) ({@link com.sun.jna.Structure.ByReference or explicitly})<br>struct by value (member of struct) ({@link com.sun.jna.Structure.ByValue or explicitly})</td><td>{@link com.sun.jna.Structure}</td></tr>
|
||||
<tr><td>union</td><td>same as <code>Structure</code></td><td>{@link com.sun.jna.Union}</td></tr>
|
||||
<tr><td>struct[]</td><td>array of structs, contiguous in memory</td><td>{@link com.sun.jna.Structure Structure[]}</td></tr>
|
||||
<tr><td>void (*FP)()</td><td>function pointer (Java or native)</td><td>{@link com.sun.jna.Callback}</td></tr>
|
||||
<tr><td>pointer (<T> *)</td><td>same as <code>Pointer</code></td><td>{@link com.sun.jna.PointerType}</td></tr>
|
||||
<tr><td>other</td><td>integer type</td><td>{@link com.sun.jna.IntegerType}</td></tr>
|
||||
<tr><td>other</td><td>custom mapping, depends on definition</td><td>{@link com.sun.jna.NativeMapped}</td></tr>
|
||||
</table>
|
||||
</center>
|
||||
<p>
|
||||
@@ -144,8 +173,8 @@ Java types must be chosen to match native types of the same size. Following are
|
||||
single call. If the native code keeps a reference to the memory, use {@link
|
||||
com.sun.jna.Memory} or {@link java.nio.Buffer} instead.
|
||||
<li>Primitive arrays and structures as members of a structure are overlaid on the parent structure memory.
|
||||
<li>Bitfields must be manully packed into an integer type.
|
||||
<li>All other types must eventually be converted to one of the types in this table. Methods with arguments or return values of types other than these must either use types deriving from {@link com.sun.jna.NativeMapped} or supply type conversion information for the unsupported types.
|
||||
<li>Bitfields must be manually packed into an integer type.
|
||||
<li>All other types must eventually be converted to one of the types in the this table. Methods with arguments or return values of types other than these must either use types deriving from {@link com.sun.jna.NativeMapped} or supply type conversion information for the unsupported types.
|
||||
<li>Type mapping behavior may be customized by providing a {@link com.sun.jna.TypeMapper} for the {@link com.sun.jna.Library#OPTION_TYPE_MAPPER} option when initializing a library interface. See {@link com.sun.jna.win32.W32APITypeMapper} for an example which provides custom conversion of boolean and String types. You are free to use whatever types are convenient in your defined interfaces, but all custom types <em>must</em> provide a mapping to one of the basic or derived types listed above.
|
||||
<li>Type mapping may also be customized on a per-class basis for user-defined types by making the user-defined type implement the {@link com.sun.jna.NativeMapped} interface.
|
||||
<li><code>Structure</code> and <code>Union</code> are <em>not</em> converted to <code>Pointer</code> when passed by value.
|
||||
@@ -589,6 +618,11 @@ method. On read, all non-pointer-based fields will be initialized from native
|
||||
memory. Structure, String, and WString members will <em>not</em> be
|
||||
initialized unless they are selected via {@link com.sun.jna.Union#setType}.
|
||||
|
||||
<a name="last-error"></a>
|
||||
<h3>Obtaining "last" error</h3>
|
||||
If a function sets the system error property
|
||||
(<code><a href="http://www.opengroup.org/onlinepubs/009695399/functions/errno.html">errno</a></code> or <code><a href="http://msdn.microsoft.com/en-us/library/ms679360(VS.85).aspx">GetLastError()</a></code>), the error code will be thrown as a {@link com.sun.jna.LastErrorException} if you declare the exception in your JNA mapping. Alternatively, you can use {@link com.sun.jna.Native#getLastError()} to retrieve it, providing that {@link com.sun.jna.Native#setPreserveLastError(boolean)} has been called with a <code>true</code> value. Throwing an exception is preferred since it has better performance.
|
||||
|
||||
<a name="java-objects"></a>
|
||||
<h3>Arbitrary Java Object arguments/return values</h3>
|
||||
In some cases, such as invoking native VM functions directly, it is necessary
|
||||
@@ -614,14 +648,25 @@ The method {@link com.sun.jna.NativeLibrary#getGlobalVariableAddress} may be use
|
||||
<a href="#toc">Table of Contents</a>
|
||||
<a name="crash-protection"></a>
|
||||
<h2>VM Crash Protection</h2>
|
||||
It is not uncommon when defining a new library and writing tests to encounter memory access errors which crash the VM. These are often caused by improper mappings or invalid arguments passed to the native library. To generate Java errors instead of crashing the VM, call {@link com.sun.jna.Native#setProtected Native.setProtected(true)}</code>. Not all platforms support this protection; if not, the value of {@link com.sun.jna.Native#isProtected} will remain <code>false</code>.
|
||||
It is not uncommon when defining a new library and writing tests to encounter memory access errors which crash the VM. These are often caused by improper mappings or invalid arguments passed to the native library. To generate Java errors instead of crashing the VM, call {@link com.sun.jna.Native#setProtected Native.setProtected(true)}</code>. Not all platforms support this protection; if not, the value of {@link com.sun.jna.Native#isProtected} will remain <code>false</code>.<p>
|
||||
NOTE: When protected mode is enabled, you should make use of the jsig library, if available (see <a href="http://java.sun.com/j2se/1.4.2/docs/guide/vm/signal-chaining.html">Signal Chaining</a>) to avoid interfering with the JVM's use of signals. In short, set the environment variable <code>LD_PRELOAD</code> (or <code>LD_PRELOAD_64</code>) to the path to <code>libjsig.so</code> in your JRE lib directory (usually ${java.home}/lib/${os.arch}/libjsig.so) before launching your Java application.
|
||||
|
||||
|
||||
<p>
|
||||
<a href="#toc">Table of Contents</a>
|
||||
<a name="performance"></a>
|
||||
<h2>Performance</h2>
|
||||
<h3>Use direct mapping of methods</h3>
|
||||
Using <a href="#direct-mapping">direct mapping</a> of methods makes native
|
||||
calls more efficiently than does interface mapping. Direct mapping does not
|
||||
support varargs calls or arrays of Pointer, String, or WString as an argument
|
||||
or return value.
|
||||
<h3>Avoid type mapping</h3>
|
||||
Type mapping incurs additional overhead on each function call. You can avoid
|
||||
this by ensuring that your arguments and/or return types are already primitive
|
||||
types.
|
||||
<h3>Pointer/Array/Buffer Variants</h3>
|
||||
Java primitive arrays are generally slower to use than memory
|
||||
Java primitive arrays are generally slower to use than direct memory
|
||||
(Pointer, Memory, or ByReference) or NIO buffers, since the Java memory has to
|
||||
be pinned and possibly copied across the native call, since the Java array is not necessarily contiguously allocated.
|
||||
<h3>Large Structures</h3>
|
||||
@@ -631,7 +676,7 @@ a performance hit using reflection to walk through all the fields. Structure
|
||||
auto-synch can be disabled by calling
|
||||
{@link com.sun.jna.Structure#setAutoSynch} with a <code>false</code> parameter.
|
||||
It is then up to you to use {@link com.sun.jna.Structure#readField(String)}
|
||||
and {@link com.sun.jna.Structure#writeField(String)}/{@link
|
||||
and {@link com.sun.jna.Structure#writeField(String)} or {@link
|
||||
com.sun.jna.Structure#writeField(String,Object)} to synch with just the fields
|
||||
of interest.
|
||||
</body>
|
||||
|
||||
@@ -61,6 +61,12 @@ public class ArgumentsMarshalTest extends TestCase {
|
||||
String returnStringArrayElement(String[] args, int which);
|
||||
WString returnWideStringArrayElement(WString[] args, int which);
|
||||
Pointer returnPointerArrayElement(Pointer[] args, int which);
|
||||
|
||||
public static class TestPointerType extends PointerType {
|
||||
public TestPointerType() { }
|
||||
public TestPointerType(Pointer p) { super(p); }
|
||||
}
|
||||
TestPointerType returnPointerArrayElement(TestPointerType[] args, int which);
|
||||
CheckFieldAlignment returnPointerArrayElement(CheckFieldAlignment.ByReference[] args, int which);
|
||||
int returnRotatedArgumentCount(String[] args);
|
||||
|
||||
@@ -89,6 +95,40 @@ public class ArgumentsMarshalTest extends TestCase {
|
||||
|
||||
// Nonexistent functions
|
||||
boolean returnBooleanArgument(Object arg);
|
||||
|
||||
// Structure
|
||||
class MinTestStructure extends Structure {
|
||||
public int field;
|
||||
}
|
||||
Pointer testStructurePointerArgument(MinTestStructure s);
|
||||
|
||||
class VariableSizedStructure extends Structure {
|
||||
public int length;
|
||||
public byte[] buffer;
|
||||
public VariableSizedStructure(String arg) {
|
||||
length = arg.length() + 1;
|
||||
buffer = new byte[length];
|
||||
System.arraycopy(arg.getBytes(), 0, buffer, 0, arg.length());
|
||||
}
|
||||
}
|
||||
String returnStringFromVariableSizedStructure(VariableSizedStructure s);
|
||||
class CbStruct extends Structure {
|
||||
public static interface TestCallback extends Callback {
|
||||
int callback(int arg1, int arg2);
|
||||
}
|
||||
public TestCallback cb;
|
||||
}
|
||||
void setCallbackInStruct(CbStruct cbstruct);
|
||||
|
||||
// Union (by value)
|
||||
class TestUnion extends Union implements Structure.ByValue {
|
||||
public String f1;
|
||||
public int f2;
|
||||
}
|
||||
interface UnionCallback extends Callback {
|
||||
TestUnion invoke(TestUnion arg);
|
||||
}
|
||||
TestUnion testUnionByValueCallbackArgument(UnionCallback cb, TestUnion arg);
|
||||
}
|
||||
|
||||
TestLibrary lib;
|
||||
@@ -228,9 +268,12 @@ public class ArgumentsMarshalTest extends TestCase {
|
||||
return new Integer(value);
|
||||
}
|
||||
}
|
||||
public void testNativeMappedArgument() {
|
||||
NativeMappedLibrary lib = (NativeMappedLibrary)
|
||||
protected NativeMappedLibrary loadNativeMappedLibrary() {
|
||||
return (NativeMappedLibrary)
|
||||
Native.loadLibrary("testlib", NativeMappedLibrary.class);
|
||||
}
|
||||
public void testNativeMappedArgument() {
|
||||
NativeMappedLibrary lib = loadNativeMappedLibrary();
|
||||
final int MAGIC = 0x12345678;
|
||||
Custom arg = new Custom(MAGIC);
|
||||
assertEquals("Argument not mapped", MAGIC, lib.returnInt32Argument(arg));
|
||||
@@ -490,7 +533,7 @@ public class ArgumentsMarshalTest extends TestCase {
|
||||
|
||||
public void testPointerArrayArgument() {
|
||||
Pointer[] args = {
|
||||
new NativeString(getName()).getPointer(),
|
||||
new NativeString(getName()).getPointer(),
|
||||
null,
|
||||
new NativeString(getName()+"2").getPointer(),
|
||||
};
|
||||
@@ -500,15 +543,26 @@ public class ArgumentsMarshalTest extends TestCase {
|
||||
assertNull("Native array should be null terminated", lib.returnPointerArrayElement(args, 3));
|
||||
}
|
||||
|
||||
public void testNativeMappedArrayArgument() {
|
||||
TestLibrary.TestPointerType[] args = {
|
||||
new TestLibrary.TestPointerType(new NativeString(getName()).getPointer()),
|
||||
null,
|
||||
new TestLibrary.TestPointerType(new NativeString(getName()+"2").getPointer()),
|
||||
};
|
||||
assertEquals("Wrong value returned", args[0], lib.returnPointerArrayElement(args, 0));
|
||||
assertNull("Wrong value returned", lib.returnPointerArrayElement(args, 1));
|
||||
assertEquals("Wrong value returned", args[2], lib.returnPointerArrayElement(args, 2));
|
||||
};
|
||||
|
||||
public void testStructureByReferenceArrayArgument() {
|
||||
CheckFieldAlignment.ByReference[] args = {
|
||||
new CheckFieldAlignment.ByReference(),
|
||||
null,
|
||||
new CheckFieldAlignment.ByReference(),
|
||||
};
|
||||
assertEquals("Wrong value returned", args[0], lib.returnPointerArrayElement(args, 0));
|
||||
assertNull("Wrong value returned", lib.returnPointerArrayElement(args, 1));
|
||||
assertEquals("Wrong value returned", args[2], lib.returnPointerArrayElement(args, 2));
|
||||
assertEquals("Wrong value returned (0)", args[0], lib.returnPointerArrayElement(args, 0));
|
||||
assertNull("Wrong value returned (1)", lib.returnPointerArrayElement(args, 1));
|
||||
assertEquals("Wrong value returned (2)", args[2], lib.returnPointerArrayElement(args, 2));
|
||||
assertNull("Native array should be null terminated", lib.returnPointerArrayElement(args, 3));
|
||||
}
|
||||
|
||||
@@ -520,6 +574,64 @@ public class ArgumentsMarshalTest extends TestCase {
|
||||
Arrays.asList(args));
|
||||
}
|
||||
|
||||
public void testReadFunctionPointerAsCallback() {
|
||||
TestLibrary.CbStruct s = new TestLibrary.CbStruct();
|
||||
assertNull("Function pointer field should be null", s.cb);
|
||||
lib.setCallbackInStruct(s);
|
||||
assertNotNull("Callback field not set", s.cb);
|
||||
}
|
||||
|
||||
public void testCallProxiedFunctionPointer() {
|
||||
TestLibrary.CbStruct s = new TestLibrary.CbStruct();
|
||||
lib.setCallbackInStruct(s);
|
||||
assertEquals("Proxy to native function pointer failed: " + s.cb,
|
||||
3, s.cb.callback(1, 2));
|
||||
}
|
||||
|
||||
public void testVariableSizedStructureArgument() {
|
||||
String EXPECTED = getName();
|
||||
TestLibrary.VariableSizedStructure s =
|
||||
new TestLibrary.VariableSizedStructure(EXPECTED);
|
||||
assertEquals("Wrong string returned from variable sized struct",
|
||||
EXPECTED, lib.returnStringFromVariableSizedStructure(s));
|
||||
}
|
||||
|
||||
public void testDisableAutoSynch() {
|
||||
TestLibrary.MinTestStructure s = new TestLibrary.MinTestStructure();
|
||||
final int VALUE = 42;
|
||||
s.field = VALUE;
|
||||
s.setAutoWrite(false);
|
||||
lib.testStructurePointerArgument(s);
|
||||
assertEquals("Auto write should be disabled", 0, s.field);
|
||||
|
||||
final int EXPECTED = s.field;
|
||||
s.getPointer().setInt(0, VALUE);
|
||||
s.setAutoRead(false);
|
||||
lib.testStructurePointerArgument(s);
|
||||
assertEquals("Auto read should be disabled", EXPECTED, s.field);
|
||||
}
|
||||
|
||||
public void testUnionByValueCallbackArgument() throws Exception{
|
||||
TestLibrary.TestUnion arg = new TestLibrary.TestUnion();
|
||||
arg.setType(String.class);
|
||||
final String VALUE = getName();
|
||||
arg.f1 = VALUE;
|
||||
final boolean[] called = { false };
|
||||
final String[] cbvalue = { null };
|
||||
TestLibrary.TestUnion result = lib.testUnionByValueCallbackArgument(new TestLibrary.UnionCallback() {
|
||||
public TestLibrary.TestUnion invoke(TestLibrary.TestUnion v) {
|
||||
called[0] = true;
|
||||
v.setType(String.class);
|
||||
v.read();
|
||||
cbvalue[0] = v.f1;
|
||||
return v;
|
||||
}
|
||||
}, arg);
|
||||
assertTrue("Callback not called", called[0]);
|
||||
assertEquals("Incorrect callback union argument", VALUE, cbvalue[0]);
|
||||
assertEquals("Union value not propagated", VALUE, result.getTypedValue(String.class));
|
||||
}
|
||||
|
||||
public static void main(java.lang.String[] argList) {
|
||||
junit.textui.TestRunner.run(ArgumentsMarshalTest.class);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import com.sun.jna.ptr.DoubleByReference;
|
||||
import com.sun.jna.ptr.FloatByReference;
|
||||
import com.sun.jna.ptr.IntByReference;
|
||||
import com.sun.jna.ptr.LongByReference;
|
||||
import com.sun.jna.ptr.NativeLongByReference;
|
||||
import com.sun.jna.ptr.PointerByReference;
|
||||
import com.sun.jna.ptr.ShortByReference;
|
||||
|
||||
@@ -32,6 +33,7 @@ public class ByReferenceArgumentsTest extends TestCase {
|
||||
void incrementInt8ByReference(ByteByReference b);
|
||||
void incrementInt16ByReference(ShortByReference s);
|
||||
void incrementInt32ByReference(IntByReference i);
|
||||
void incrementNativeLongByReference(NativeLongByReference l);
|
||||
void incrementInt64ByReference(LongByReference l);
|
||||
void complementFloatByReference(FloatByReference f);
|
||||
void complementDoubleByReference(DoubleByReference d);
|
||||
@@ -62,6 +64,12 @@ public class ByReferenceArgumentsTest extends TestCase {
|
||||
lib.incrementInt32ByReference(iref);
|
||||
assertEquals("Int argument not modified", 1, iref.getValue());
|
||||
}
|
||||
public void testNativeLongByReference() {
|
||||
NativeLongByReference iref = new NativeLongByReference();
|
||||
lib.incrementNativeLongByReference(iref);
|
||||
assertEquals("Native long argument not modified",
|
||||
new NativeLong(1), iref.getValue());
|
||||
}
|
||||
public void testLongByReference() {
|
||||
LongByReference lref = new LongByReference();
|
||||
lib.incrementInt64ByReference(lref);
|
||||
|
||||
@@ -12,16 +12,19 @@
|
||||
*/
|
||||
package com.sun.jna;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import com.sun.jna.CallbacksTest.TestLibrary.CbCallback;
|
||||
import com.sun.jna.ptr.IntByReference;
|
||||
import com.sun.jna.Callback.UncaughtExceptionHandler;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import com.sun.jna.Callback.UncaughtExceptionHandler;
|
||||
import com.sun.jna.CallbacksTest.TestLibrary.CbCallback;
|
||||
import com.sun.jna.ptr.IntByReference;
|
||||
|
||||
/** Exercise callback-related functionality.
|
||||
*
|
||||
* @author twall@users.sf.net
|
||||
@@ -46,6 +49,19 @@ public class CallbacksTest extends TestCase {
|
||||
public SmallTestStructure inner;
|
||||
}
|
||||
public static interface TestLibrary extends Library {
|
||||
interface NoMethodCallback extends Callback {
|
||||
}
|
||||
interface CustomMethodCallback extends Callback {
|
||||
void invoke();
|
||||
}
|
||||
interface TooManyMethodsCallback extends Callback {
|
||||
void invoke();
|
||||
void invoke2();
|
||||
}
|
||||
interface MultipleMethodsCallback extends Callback {
|
||||
void invoke();
|
||||
void callback();
|
||||
}
|
||||
interface VoidCallback extends Callback {
|
||||
void callback();
|
||||
}
|
||||
@@ -116,11 +132,21 @@ public class CallbacksTest extends TestCase {
|
||||
}
|
||||
CbCallback callCallbackWithCallback(CbCallback cb);
|
||||
|
||||
public interface Int32CallbackX extends Callback {
|
||||
interface Int32CallbackX extends Callback {
|
||||
public int callback(int arg);
|
||||
}
|
||||
Int32CallbackX returnCallback();
|
||||
Int32CallbackX returnCallbackArgument(Int32CallbackX cb);
|
||||
|
||||
interface CustomCallback extends Callback {
|
||||
Custom callback(Custom arg1, Custom arg2);
|
||||
}
|
||||
int callInt32Callback(CustomCallback cb, int arg1, int arg2);
|
||||
|
||||
class CbStruct extends Structure {
|
||||
public Callback cb;
|
||||
}
|
||||
void callCallbackInStruct(CbStruct cbstruct);
|
||||
}
|
||||
|
||||
TestLibrary lib;
|
||||
@@ -132,6 +158,66 @@ public class CallbacksTest extends TestCase {
|
||||
lib = null;
|
||||
}
|
||||
|
||||
public void testLookupNullCallback() {
|
||||
assertNull("NULL pointer should result in null callback",
|
||||
CallbackReference.getCallback(null, null));
|
||||
try {
|
||||
CallbackReference.getCallback(TestLibrary.VoidCallback.class, new Pointer(0));
|
||||
fail("Null pointer lookup should fail");
|
||||
}
|
||||
catch(NullPointerException e) {
|
||||
}
|
||||
}
|
||||
|
||||
public void testLookupNonCallbackClass() {
|
||||
try {
|
||||
CallbackReference.getCallback(String.class, new Pointer(0));
|
||||
fail("Request for non-Callback class should fail");
|
||||
}
|
||||
catch(IllegalArgumentException e) {
|
||||
}
|
||||
}
|
||||
|
||||
public void testNoMethodCallback() {
|
||||
try {
|
||||
CallbackReference.getCallback(TestLibrary.NoMethodCallback.class, new Pointer(1));
|
||||
fail("Callback with no callback method should fail");
|
||||
}
|
||||
catch(IllegalArgumentException e) {
|
||||
}
|
||||
}
|
||||
|
||||
public void testCustomMethodCallback() {
|
||||
CallbackReference.getCallback(TestLibrary.CustomMethodCallback.class, new Pointer(1));
|
||||
}
|
||||
|
||||
public void testTooManyMethodsCallback() {
|
||||
try {
|
||||
CallbackReference.getCallback(TestLibrary.TooManyMethodsCallback.class, new Pointer(1));
|
||||
fail("Callback lookup with too many methods should fail");
|
||||
}
|
||||
catch(IllegalArgumentException e) {
|
||||
}
|
||||
}
|
||||
|
||||
public void testMultipleMethodsCallback() {
|
||||
CallbackReference.getCallback(TestLibrary.MultipleMethodsCallback.class, new Pointer(1));
|
||||
}
|
||||
|
||||
public void testNativeFunctionPointerStringValue() {
|
||||
Callback cb = CallbackReference.getCallback(TestLibrary.VoidCallback.class, new Pointer(1));
|
||||
Class cls = CallbackReference.findCallbackClass(cb.getClass());
|
||||
assertTrue("toString should include Java Callback type: " + cb + " ("
|
||||
+ cls + ")", cb.toString().indexOf(cls.getName()) != -1);
|
||||
}
|
||||
|
||||
public void testLookupSameCallback() {
|
||||
Callback cb = CallbackReference.getCallback(TestLibrary.VoidCallback.class, new Pointer(1));
|
||||
Callback cb2 = CallbackReference.getCallback(TestLibrary.VoidCallback.class, new Pointer(1));
|
||||
|
||||
assertEquals("Callback lookups for same pointer should return same Callback object", cb, cb2);
|
||||
}
|
||||
|
||||
public void testGCCallback() throws Exception {
|
||||
final boolean[] called = { false };
|
||||
TestLibrary.VoidCallback cb = new TestLibrary.VoidCallback() {
|
||||
@@ -142,16 +228,19 @@ public class CallbacksTest extends TestCase {
|
||||
lib.callVoidCallback(cb);
|
||||
assertTrue("Callback not called", called[0]);
|
||||
|
||||
Map refs = CallbackReference.callbackMap;
|
||||
Map refs = new WeakHashMap(CallbackReference.callbackMap);
|
||||
refs.putAll(CallbackReference.directCallbackMap);
|
||||
assertTrue("Callback not cached", refs.containsKey(cb));
|
||||
CallbackReference ref = (CallbackReference)refs.get(cb);
|
||||
refs = ref.proxy != null ? CallbackReference.callbackMap
|
||||
: CallbackReference.directCallbackMap;
|
||||
Pointer cbstruct = ref.cbstruct;
|
||||
|
||||
cb = null;
|
||||
System.gc();
|
||||
for (int i = 0; i < 100 && (ref.get() != null || refs.containsValue(ref)); ++i) {
|
||||
try {
|
||||
Thread.sleep(1); // Give the GC a chance to run
|
||||
Thread.sleep(10); // Give the GC a chance to run
|
||||
} finally {}
|
||||
}
|
||||
assertNull("Callback not GC'd", ref.get());
|
||||
@@ -159,9 +248,12 @@ public class CallbacksTest extends TestCase {
|
||||
|
||||
ref = null;
|
||||
System.gc();
|
||||
for (int i = 0; i < 100 && cbstruct.peer != 0; ++i) {
|
||||
for (int i = 0; i < 100 && (cbstruct.peer != 0 || refs.size() > 0); ++i) {
|
||||
// Flush weak hash map
|
||||
refs.size();
|
||||
try {
|
||||
Thread.sleep(1); // Give the GC a chance to run
|
||||
Thread.sleep(10); // Give the GC a chance to run
|
||||
System.gc();
|
||||
} finally {}
|
||||
}
|
||||
assertEquals("Callback trampoline not freed", 0, cbstruct.peer);
|
||||
@@ -175,7 +267,7 @@ public class CallbacksTest extends TestCase {
|
||||
};
|
||||
assertEquals("Wrong callback interface",
|
||||
TestLibrary.Int32Callback.class,
|
||||
Native.findCallbackClass(cb.getClass()));
|
||||
CallbackReference.findCallbackClass(cb.getClass()));
|
||||
}
|
||||
|
||||
public void testCallInt32Callback() {
|
||||
@@ -218,15 +310,20 @@ public class CallbacksTest extends TestCase {
|
||||
|
||||
public void testCallFloatCallback() {
|
||||
final boolean[] called = { false };
|
||||
final float[] args = { 0, 0 };
|
||||
TestLibrary.FloatCallback cb = new TestLibrary.FloatCallback() {
|
||||
public float callback(float arg, float arg2) {
|
||||
called[0] = true;
|
||||
args[0] = arg;
|
||||
args[1] = arg2;
|
||||
return arg + arg2;
|
||||
}
|
||||
};
|
||||
final float EXPECTED = FLOAT_MAGIC*3;
|
||||
float value = lib.callFloatCallback(cb, FLOAT_MAGIC, FLOAT_MAGIC*2);
|
||||
assertTrue("Callback not called", called[0]);
|
||||
assertEquals("Wrong first argument", FLOAT_MAGIC, args[0], 0);
|
||||
assertEquals("Wrong second argument", FLOAT_MAGIC*2, args[1], 0);
|
||||
assertEquals("Wrong callback value", EXPECTED, value, 0);
|
||||
|
||||
value = lib.callFloatCallback(cb, -1f, -2f);
|
||||
@@ -235,15 +332,20 @@ public class CallbacksTest extends TestCase {
|
||||
|
||||
public void testCallDoubleCallback() {
|
||||
final boolean[] called = { false };
|
||||
final double[] args = { 0, 0 };
|
||||
TestLibrary.DoubleCallback cb = new TestLibrary.DoubleCallback() {
|
||||
public double callback(double arg, double arg2) {
|
||||
called[0] = true;
|
||||
args[0] = arg;
|
||||
args[1] = arg2;
|
||||
return arg + arg2;
|
||||
}
|
||||
};
|
||||
final double EXPECTED = DOUBLE_MAGIC*3;
|
||||
double value = lib.callDoubleCallback(cb, DOUBLE_MAGIC, DOUBLE_MAGIC*2);
|
||||
assertTrue("Callback not called", called[0]);
|
||||
assertEquals("Wrong first argument", DOUBLE_MAGIC, args[0], 0);
|
||||
assertEquals("Wrong second argument", DOUBLE_MAGIC*2, args[1], 0);
|
||||
assertEquals("Wrong callback value", EXPECTED, value, 0);
|
||||
|
||||
value = lib.callDoubleCallback(cb, -1d, -2d);
|
||||
@@ -263,7 +365,7 @@ public class CallbacksTest extends TestCase {
|
||||
};
|
||||
SmallTestStructure value = lib.callStructureCallback(cb, s);
|
||||
assertTrue("Callback not called", called[0]);
|
||||
assertEquals("Wrong callback argument", s, cbarg[0]);
|
||||
assertEquals("Wrong argument passed to callback", s, cbarg[0]);
|
||||
assertEquals("Wrong structure return", s, value);
|
||||
}
|
||||
|
||||
@@ -378,16 +480,10 @@ public class CallbacksTest extends TestCase {
|
||||
return o instanceof Custom && ((Custom)o).value == value;
|
||||
}
|
||||
}
|
||||
public static interface CustomCallback extends Callback {
|
||||
Custom callback(Custom arg1, Custom arg2);
|
||||
}
|
||||
public static interface NativeMappedLibrary extends Library {
|
||||
int callInt32Callback(CustomCallback cb, int arg1, int arg2);
|
||||
}
|
||||
public void testCallNativeMappedCallback() {
|
||||
final boolean[] called = {false};
|
||||
final Custom[] cbargs = { null, null};
|
||||
CustomCallback cb = new CustomCallback() {
|
||||
TestLibrary.CustomCallback cb = new TestLibrary.CustomCallback() {
|
||||
public Custom callback(Custom arg, Custom arg2) {
|
||||
called[0] = true;
|
||||
cbargs[0] = arg;
|
||||
@@ -395,8 +491,6 @@ public class CallbacksTest extends TestCase {
|
||||
return new Custom(arg.value + arg2.value);
|
||||
}
|
||||
};
|
||||
NativeMappedLibrary lib = (NativeMappedLibrary)
|
||||
Native.loadLibrary("testlib", NativeMappedLibrary.class);
|
||||
int value = lib.callInt32Callback(cb, 1, 2);
|
||||
assertTrue("Callback not called", called[0]);
|
||||
assertEquals("Wrong callback argument 1", new Custom(1), cbargs[0]);
|
||||
@@ -533,6 +627,26 @@ public class CallbacksTest extends TestCase {
|
||||
assertEquals("Callback reference should be reused", cb, cb2);
|
||||
}
|
||||
|
||||
public void testDefaultCallbackExceptionHandler() {
|
||||
final RuntimeException ERROR = new RuntimeException(getName());
|
||||
PrintStream ps = System.err;
|
||||
ByteArrayOutputStream s = new ByteArrayOutputStream();
|
||||
System.setErr(new PrintStream(s));
|
||||
try {
|
||||
TestLibrary.CbCallback cb = new TestLibrary.CbCallback() {
|
||||
public CbCallback callback(CbCallback arg) {
|
||||
throw ERROR;
|
||||
}
|
||||
};
|
||||
TestLibrary.CbCallback cb2 = lib.callCallbackWithCallback(cb);
|
||||
String output = s.toString();
|
||||
assertTrue("Default handler not called", output.length() > 0);
|
||||
}
|
||||
finally {
|
||||
System.setErr(ps);
|
||||
}
|
||||
}
|
||||
|
||||
/* Most Callbacks are wrapped in DefaultCallbackProxy, which catches their
|
||||
* exceptions.
|
||||
*/
|
||||
@@ -611,61 +725,7 @@ public class CallbacksTest extends TestCase {
|
||||
Native.getCallbackExceptionHandler());
|
||||
}
|
||||
|
||||
public static interface CallbackTestLibrary extends Library {
|
||||
interface Int32Callback extends Callback {
|
||||
float callback(float arg, float arg2);
|
||||
}
|
||||
float callInt32Callback(Int32Callback c, float arg, float arg2);
|
||||
}
|
||||
|
||||
public void testCallbackTypeMappingFromLibrary() throws Exception {
|
||||
final DefaultTypeMapper mapper = new DefaultTypeMapper();
|
||||
Map options = new HashMap() {
|
||||
{ put(Library.OPTION_TYPE_MAPPER, mapper); }
|
||||
};
|
||||
CallbackTestLibrary lib = (CallbackTestLibrary)
|
||||
Native.loadLibrary("testlib", CallbackTestLibrary.class, options);
|
||||
|
||||
// Convert java floats into native integers and back
|
||||
TypeConverter converter = new TypeConverter() {
|
||||
public Object fromNative(Object value, FromNativeContext context) {
|
||||
return new Float(((Integer)value).intValue());
|
||||
}
|
||||
public Class nativeType() {
|
||||
return Integer.class;
|
||||
}
|
||||
public Object toNative(Object value, ToNativeContext ctx) {
|
||||
return new Integer(Math.round(((Float)value).floatValue()));
|
||||
}
|
||||
};
|
||||
mapper.addTypeConverter(float.class, converter);
|
||||
CallbackTestLibrary.Int32Callback cb = new CallbackTestLibrary.Int32Callback() {
|
||||
public float callback(float arg, float arg2) {
|
||||
return arg + arg2;
|
||||
}
|
||||
};
|
||||
assertEquals("Wrong type mapper for callback class", mapper,
|
||||
Native.getTypeMapper(CallbackTestLibrary.Int32Callback.class));
|
||||
assertEquals("Wrong type mapper for callback object", mapper,
|
||||
Native.getTypeMapper(cb.getClass()));
|
||||
|
||||
assertEquals("Wrong type mapper used in callback invocation",
|
||||
-2, lib.callInt32Callback(cb, -1, -1), 0);
|
||||
}
|
||||
|
||||
private static class TestCallback implements Callback {
|
||||
public static final TypeMapper TYPE_MAPPER = new DefaultTypeMapper();
|
||||
public void callback() { }
|
||||
}
|
||||
public void testCallbackTypeMappingFromCallback() throws Exception {
|
||||
assertEquals("Wrong type mapper for callback class",
|
||||
TestCallback.TYPE_MAPPER,
|
||||
Native.getTypeMapper(TestCallback.class));
|
||||
}
|
||||
|
||||
public void testInvokeCallback() {
|
||||
TestLibrary lib = (TestLibrary)
|
||||
Native.loadLibrary("testlib", TestLibrary.class);
|
||||
TestLibrary.Int32CallbackX cb = lib.returnCallback();
|
||||
assertNotNull("Callback should not be null", cb);
|
||||
assertEquals("Callback should be callable", 1, cb.callback(1));
|
||||
@@ -681,21 +741,14 @@ public class CallbacksTest extends TestCase {
|
||||
cb, lib.returnCallbackArgument(cb));
|
||||
}
|
||||
|
||||
static class CbStruct extends Structure {
|
||||
public Callback cb;
|
||||
}
|
||||
interface CbTest extends Library {
|
||||
public void callCallbackInStruct(CbStruct cbstruct);
|
||||
}
|
||||
public void testCallCallbackInStructure() {
|
||||
final boolean[] flag = {false};
|
||||
final CbStruct s = new CbStruct();
|
||||
final TestLibrary.CbStruct s = new TestLibrary.CbStruct();
|
||||
s.cb = new Callback() {
|
||||
public void callback() {
|
||||
flag[0] = true;
|
||||
}
|
||||
};
|
||||
CbTest lib = (CbTest)Native.loadLibrary("testlib", CbTest.class);
|
||||
lib.callCallbackInStruct(s);
|
||||
assertTrue("Callback not invoked", flag[0]);
|
||||
}
|
||||
@@ -721,6 +774,107 @@ public class CallbacksTest extends TestCase {
|
||||
lib.callVoidCallback(cb);
|
||||
}
|
||||
|
||||
public static interface CallbackTestLibrary extends Library {
|
||||
final TypeMapper _MAPPER = new DefaultTypeMapper() {
|
||||
{
|
||||
// Convert java doubles into native integers and back
|
||||
TypeConverter converter = new TypeConverter() {
|
||||
public Object fromNative(Object value, FromNativeContext context) {
|
||||
return new Double(((Integer)value).intValue());
|
||||
}
|
||||
public Class nativeType() {
|
||||
return Integer.class;
|
||||
}
|
||||
public Object toNative(Object value, ToNativeContext ctx) {
|
||||
return new Integer(((Double)value).intValue());
|
||||
}
|
||||
};
|
||||
addTypeConverter(double.class, converter);
|
||||
converter = new TypeConverter() {
|
||||
public Object fromNative(Object value, FromNativeContext context) {
|
||||
return new Float(((Long)value).intValue());
|
||||
}
|
||||
public Class nativeType() {
|
||||
return Long.class;
|
||||
}
|
||||
public Object toNative(Object value, ToNativeContext ctx) {
|
||||
return new Long(((Float)value).longValue());
|
||||
}
|
||||
};
|
||||
addTypeConverter(float.class, converter);
|
||||
}
|
||||
};
|
||||
final Map _OPTIONS = new HashMap() {
|
||||
{
|
||||
put(Library.OPTION_TYPE_MAPPER, _MAPPER);
|
||||
}
|
||||
};
|
||||
interface DoubleCallback extends Callback {
|
||||
double callback(double arg, double arg2);
|
||||
}
|
||||
double callInt32Callback(DoubleCallback c, double arg, double arg2);
|
||||
interface FloatCallback extends Callback {
|
||||
float callback(float arg, float arg2);
|
||||
}
|
||||
float callInt64Callback(FloatCallback c, float arg, float arg2);
|
||||
}
|
||||
|
||||
protected CallbackTestLibrary loadCallbackTestLibrary() {
|
||||
return (CallbackTestLibrary)
|
||||
Native.loadLibrary("testlib", CallbackTestLibrary.class, CallbackTestLibrary._OPTIONS);
|
||||
}
|
||||
|
||||
/** This test is here instead of NativeTest in order to facilitate running
|
||||
the exact same test on a direct-mapped library without the tests
|
||||
interfering with one another due to persistent/cached state in library
|
||||
loading.
|
||||
*/
|
||||
public void testCallbackUsesTypeMapper() throws Exception {
|
||||
CallbackTestLibrary lib = loadCallbackTestLibrary();
|
||||
|
||||
final double[] ARGS = new double[2];
|
||||
|
||||
CallbackTestLibrary.DoubleCallback cb = new CallbackTestLibrary.DoubleCallback() {
|
||||
public double callback(double arg, double arg2) {
|
||||
ARGS[0] = arg;
|
||||
ARGS[1] = arg2;
|
||||
return arg + arg2;
|
||||
}
|
||||
};
|
||||
assertEquals("Wrong type mapper for callback class", lib._MAPPER,
|
||||
Native.getTypeMapper(CallbackTestLibrary.DoubleCallback.class));
|
||||
assertEquals("Wrong type mapper for callback object", lib._MAPPER,
|
||||
Native.getTypeMapper(cb.getClass()));
|
||||
|
||||
double result = lib.callInt32Callback(cb, -1, -1);
|
||||
assertEquals("Wrong callback argument 1", -1, ARGS[0], 0);
|
||||
assertEquals("Wrong callback argument 2", -1, ARGS[1], 0);
|
||||
assertEquals("Incorrect result of callback invocation", -2, result, 0);
|
||||
}
|
||||
|
||||
public void testCallbackUsesTypeMapperWithDifferentReturnTypeSize() throws Exception {
|
||||
CallbackTestLibrary lib = loadCallbackTestLibrary();
|
||||
|
||||
final float[] ARGS = new float[2];
|
||||
|
||||
CallbackTestLibrary.FloatCallback cb = new CallbackTestLibrary.FloatCallback() {
|
||||
public float callback(float arg, float arg2) {
|
||||
ARGS[0] = arg;
|
||||
ARGS[1] = arg2;
|
||||
return arg + arg2;
|
||||
}
|
||||
};
|
||||
assertEquals("Wrong type mapper for callback class", lib._MAPPER,
|
||||
Native.getTypeMapper(CallbackTestLibrary.FloatCallback.class));
|
||||
assertEquals("Wrong type mapper for callback object", lib._MAPPER,
|
||||
Native.getTypeMapper(cb.getClass()));
|
||||
|
||||
float result = lib.callInt64Callback(cb, -1, -1);
|
||||
assertEquals("Wrong callback argument 1", -1, ARGS[0], 0);
|
||||
assertEquals("Wrong callback argument 2", -1, ARGS[1], 0);
|
||||
assertEquals("Incorrect result of callback invocation", -2, result, 0);
|
||||
}
|
||||
|
||||
public static void main(java.lang.String[] argList) {
|
||||
junit.textui.TestRunner.run(CallbacksTest.class);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
/* Copyright (c) 2009 Timothy Wall, All Rights Reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
* <p/>
|
||||
* This library 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 for more details.
|
||||
*/
|
||||
package com.sun.jna;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.LongBuffer;
|
||||
import java.nio.ShortBuffer;
|
||||
|
||||
/** Exercise a range of native methods.
|
||||
*
|
||||
* @author twall@users.sf.net
|
||||
*/
|
||||
public class DirectArgumentsMarshalTest extends ArgumentsMarshalTest {
|
||||
|
||||
public static class DirectTestLibrary implements TestLibrary {
|
||||
/** Dummy. Automatically fail when passed an object. */
|
||||
public String returnStringArgument(Object arg) {throw new IllegalArgumentException(arg.getClass().getName()); }
|
||||
public native boolean returnBooleanArgument(boolean arg);
|
||||
public native byte returnInt8Argument(byte arg);
|
||||
public native char returnWideCharArgument(char arg);
|
||||
public native short returnInt16Argument(short arg);
|
||||
public native int returnInt32Argument(int i);
|
||||
public native long returnInt64Argument(long l);
|
||||
public native NativeLong returnLongArgument(NativeLong l);
|
||||
public native float returnFloatArgument(float f);
|
||||
public native double returnDoubleArgument(double d);
|
||||
public native String returnStringArgument(String s);
|
||||
public native WString returnWStringArgument(WString s);
|
||||
public native Pointer returnPointerArgument(Pointer p);
|
||||
public String returnStringArrayElement(String[] args, int which) {throw new UnsupportedOperationException();}
|
||||
public WString returnWideStringArrayElement(WString[] args, int which) {throw new UnsupportedOperationException();}
|
||||
public Pointer returnPointerArrayElement(Pointer[] args, int which) {throw new UnsupportedOperationException();}
|
||||
public TestPointerType returnPointerArrayElement(TestPointerType[] args, int which) {throw new UnsupportedOperationException();}
|
||||
public CheckFieldAlignment returnPointerArrayElement(CheckFieldAlignment.ByReference[] args, int which) {throw new UnsupportedOperationException();}
|
||||
public int returnRotatedArgumentCount(String[] args) {throw new UnsupportedOperationException();}
|
||||
|
||||
public native long checkInt64ArgumentAlignment(int i, long j, int i2, long j2);
|
||||
public native double checkDoubleArgumentAlignment(float i, double j, float i2, double j2);
|
||||
public native Pointer testStructurePointerArgument(CheckFieldAlignment p);
|
||||
public native double testStructureByValueArgument(CheckFieldAlignment.ByValue p);
|
||||
public int testStructureArrayInitialization(CheckFieldAlignment[] p, int len) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
public void modifyStructureArray(CheckFieldAlignment[] p, int length) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public native int fillInt8Buffer(byte[] buf, int len, byte value);
|
||||
public native int fillInt16Buffer(short[] buf, int len, short value);
|
||||
public native int fillInt32Buffer(int[] buf, int len, int value);
|
||||
public native int fillInt64Buffer(long[] buf, int len, long value);
|
||||
|
||||
// ByteBuffer alternative definitions
|
||||
public native int fillInt8Buffer(ByteBuffer buf, int len, byte value);
|
||||
public native int fillInt16Buffer(ByteBuffer buf, int len, short value);
|
||||
public native int fillInt32Buffer(ByteBuffer buf, int len, int value);
|
||||
public native int fillInt64Buffer(ByteBuffer buf, int len, long value);
|
||||
|
||||
// {Short,Int,Long}Buffer alternative definitions
|
||||
public native int fillInt16Buffer(ShortBuffer buf, int len, short value);
|
||||
public native int fillInt32Buffer(IntBuffer buf, int len, int value);
|
||||
public native int fillInt64Buffer(LongBuffer buf, int len, long value);
|
||||
|
||||
// dummy to avoid causing Native.register to fail
|
||||
public boolean returnBooleanArgument(Object arg) {throw new IllegalArgumentException();}
|
||||
|
||||
public native Pointer testStructurePointerArgument(MinTestStructure s);
|
||||
public native String returnStringFromVariableSizedStructure(VariableSizedStructure s);
|
||||
public native void setCallbackInStruct(CbStruct s);
|
||||
public native TestUnion testUnionByValueCallbackArgument(UnionCallback cb, TestUnion arg);
|
||||
|
||||
static {
|
||||
Native.register("testlib");
|
||||
}
|
||||
}
|
||||
|
||||
/* Override original. */
|
||||
protected void setUp() {
|
||||
lib = new DirectTestLibrary();
|
||||
}
|
||||
|
||||
public static class DirectNativeMappedLibrary implements NativeMappedLibrary {
|
||||
public native int returnInt32Argument(Custom arg);
|
||||
static {
|
||||
Native.register("testlib");
|
||||
}
|
||||
}
|
||||
protected NativeMappedLibrary loadNativeMappedLibrary() {
|
||||
return new DirectNativeMappedLibrary();
|
||||
}
|
||||
|
||||
// This test crashes on w32 IBM J9 unless -Xint is used
|
||||
// (jvmwi3260-20080415_18762)
|
||||
public void testWideCharArgument() {
|
||||
if (Platform.isWindows()
|
||||
&& "IBM".equals(System.getProperty("java.vm.vendor"))) {
|
||||
fail("XFAIL, crash avoided");
|
||||
}
|
||||
super.testWideCharArgument();
|
||||
}
|
||||
// This test crashes on w32 IBM J9 unless -Xint is used
|
||||
// (jvmwi3260-20080415_18762)
|
||||
public void testWStringArgumentReturn() {
|
||||
if (Platform.isWindows()
|
||||
&& "IBM".equals(System.getProperty("java.vm.vendor"))) {
|
||||
fail("XFAIL, crash avoided");
|
||||
}
|
||||
super.testWStringArgumentReturn();
|
||||
}
|
||||
|
||||
// Override tests not yet supported
|
||||
public void testStringArrayArgument() { }
|
||||
public void testWriteStructureArrayArgumentMemory() { }
|
||||
public void testUninitializedStructureArrayArgument() { }
|
||||
public void testRejectNoncontiguousStructureArrayArgument() { }
|
||||
public void testWideStringArrayArgument() { }
|
||||
public void testPointerArrayArgument() { }
|
||||
public void testNativeMappedArrayArgument() { }
|
||||
public void testStructureByReferenceArrayArgument() { }
|
||||
public void testModifiedCharArrayArgument() { }
|
||||
|
||||
public static void main(java.lang.String[] argList) {
|
||||
junit.textui.TestRunner.run(DirectArgumentsMarshalTest.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/* Copyright (c) 2009 Timothy Wall, All Rights Reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
* <p/>
|
||||
* This library 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 for more details.
|
||||
*/
|
||||
package com.sun.jna;
|
||||
|
||||
import com.sun.jna.ptr.ByteByReference;
|
||||
import com.sun.jna.ptr.DoubleByReference;
|
||||
import com.sun.jna.ptr.FloatByReference;
|
||||
import com.sun.jna.ptr.IntByReference;
|
||||
import com.sun.jna.ptr.LongByReference;
|
||||
import com.sun.jna.ptr.NativeLongByReference;
|
||||
import com.sun.jna.ptr.PointerByReference;
|
||||
import com.sun.jna.ptr.ShortByReference;
|
||||
|
||||
/** Exercise a range of native methods.
|
||||
*
|
||||
* @author twall@users.sf.net
|
||||
*/
|
||||
public class DirectByReferenceArgumentsTest extends ByReferenceArgumentsTest {
|
||||
|
||||
public static class DirectTestLibrary implements TestLibrary {
|
||||
|
||||
public native void incrementInt8ByReference(ByteByReference b);
|
||||
public native void incrementInt16ByReference(ShortByReference s);
|
||||
public native void incrementInt32ByReference(IntByReference i);
|
||||
public native void incrementNativeLongByReference(NativeLongByReference i);
|
||||
public native void incrementInt64ByReference(LongByReference l);
|
||||
public native void complementFloatByReference(FloatByReference f);
|
||||
public native void complementDoubleByReference(DoubleByReference d);
|
||||
public native void setPointerByReferenceNull(PointerByReference p);
|
||||
|
||||
static {
|
||||
Native.register("testlib");
|
||||
}
|
||||
}
|
||||
|
||||
protected void setUp() {
|
||||
lib = new DirectTestLibrary();
|
||||
}
|
||||
|
||||
public static void main(java.lang.String[] argList) {
|
||||
junit.textui.TestRunner.run(DirectByReferenceArgumentsTest.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/* Copyright (c) 2009 Timothy Wall, All Rights Reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
* <p/>
|
||||
* This library 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 for more details.
|
||||
*/
|
||||
package com.sun.jna;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.sun.jna.ptr.IntByReference;
|
||||
|
||||
/** Exercise callback-related functionality.
|
||||
*
|
||||
* @author twall@users.sf.net
|
||||
*/
|
||||
public class DirectCallbacksTest extends CallbacksTest {
|
||||
|
||||
public static class DirectTestLibrary implements TestLibrary {
|
||||
public native void callVoidCallback(VoidCallbackCustom c);
|
||||
public native boolean callBooleanCallback(BooleanCallback c, boolean arg, boolean arg2);
|
||||
public native byte callInt8Callback(ByteCallback c, byte arg, byte arg2);
|
||||
public native short callInt16Callback(ShortCallback c, short arg, short arg2);
|
||||
public native int callInt32Callback(Int32Callback c, int arg, int arg2);
|
||||
public native NativeLong callNativeLongCallback(NativeLongCallback c, NativeLong arg, NativeLong arg2);
|
||||
public native long callInt64Callback(Int64Callback c, long arg, long arg2);
|
||||
public native float callFloatCallback(FloatCallback c, float arg, float arg2);
|
||||
public native double callDoubleCallback(DoubleCallback c, double arg, double arg2);
|
||||
public native SmallTestStructure callStructureCallback(StructureCallback c, SmallTestStructure arg);
|
||||
public native String callStringCallback(StringCallback c, String arg);
|
||||
public native WString callWideStringCallback(WideStringCallback c, WString arg);
|
||||
public Pointer callStringArrayCallback(StringArrayCallback c, String[] arg) { throw new UnsupportedOperationException(); }
|
||||
public native int callCallbackWithByReferenceArgument(CopyArgToByReference cb, int arg, IntByReference result);
|
||||
public native TestStructure.ByValue callCallbackWithStructByValue(TestStructure.TestCallback callback, TestStructure.ByValue cbstruct);
|
||||
public native CbCallback callCallbackWithCallback(CbCallback cb);
|
||||
public native Int32CallbackX returnCallback();
|
||||
public native Int32CallbackX returnCallbackArgument(Int32CallbackX cb);
|
||||
public native void callVoidCallback(VoidCallback c);
|
||||
|
||||
public native int callInt32Callback(CustomCallback cb, int arg1, int arg2);
|
||||
public native void callCallbackInStruct(CbStruct s);
|
||||
|
||||
static {
|
||||
Native.register("testlib");
|
||||
}
|
||||
}
|
||||
|
||||
protected void setUp() {
|
||||
lib = new DirectTestLibrary();
|
||||
}
|
||||
|
||||
public static class DirectCallbackTestLibrary implements CallbackTestLibrary {
|
||||
public native double callInt32Callback(DoubleCallback c, double arg, double arg2);
|
||||
public native float callInt64Callback(FloatCallback c, float arg, float arg2);
|
||||
static {
|
||||
Native.register(NativeLibrary.getInstance("testlib", _OPTIONS));
|
||||
}
|
||||
}
|
||||
|
||||
protected CallbackTestLibrary loadCallbackTestLibrary() {
|
||||
return new DirectCallbackTestLibrary();
|
||||
}
|
||||
|
||||
// Currently unsupported tests
|
||||
public void testCallStringArrayCallback() { }
|
||||
public void testCallbackExceptionHandlerWithCallbackProxy() { }
|
||||
|
||||
public static void main(java.lang.String[] argList) {
|
||||
junit.textui.TestRunner.run(DirectCallbacksTest.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/* Copyright (c) 2009 Timothy Wall, All Rights Reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
* <p/>
|
||||
* This library 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 for more details.
|
||||
*/
|
||||
package com.sun.jna;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import com.sun.jna.ReturnTypesTest.TestLibrary.SimpleStructure;
|
||||
import com.sun.jna.ReturnTypesTest.TestLibrary.TestStructure;
|
||||
import com.sun.jna.ReturnTypesTest.TestLibrary.TestSmallStructure;
|
||||
|
||||
/** Exercise a range of native methods.
|
||||
*
|
||||
* @author twall@users.sf.net
|
||||
*/
|
||||
public class DirectReturnTypesTest extends ReturnTypesTest {
|
||||
|
||||
public static class DirectTestLibrary implements TestLibrary {
|
||||
|
||||
public Object returnObjectArgument(Object s) {
|
||||
throw new IllegalArgumentException(s.getClass().getName());
|
||||
}
|
||||
public TestObject returnObjectArgument(TestObject s) {
|
||||
throw new IllegalArgumentException(s.getClass().getName());
|
||||
}
|
||||
public native boolean returnFalse();
|
||||
public native boolean returnTrue();
|
||||
public native int returnInt32Zero();
|
||||
public native int returnInt32Magic();
|
||||
public native long returnInt64Zero();
|
||||
public native long returnInt64Magic();
|
||||
public native NativeLong returnLongZero();
|
||||
public native NativeLong returnLongMagic();
|
||||
public native float returnFloatZero();
|
||||
public native float returnFloatMagic();
|
||||
public native double returnDoubleZero();
|
||||
public native double returnDoubleMagic();
|
||||
public native String returnStringMagic();
|
||||
public native WString returnWStringMagic();
|
||||
public native SimpleStructure returnStaticTestStructure();
|
||||
public native SimpleStructure returnNullTestStructure();
|
||||
public native TestSmallStructure.ByValue returnSmallStructureByValue();
|
||||
public native TestStructure.ByValue returnStructureByValue();
|
||||
|
||||
public Pointer[] returnPointerArgument(Pointer[] arg) {throw new UnsupportedOperationException();}
|
||||
public String[] returnPointerArgument(String[] arg) {throw new UnsupportedOperationException();}
|
||||
public WString[] returnPointerArgument(WString[] arg) {throw new UnsupportedOperationException();}
|
||||
|
||||
static {
|
||||
Native.register("testlib");
|
||||
}
|
||||
}
|
||||
|
||||
protected void setUp() {
|
||||
lib = new DirectTestLibrary();
|
||||
}
|
||||
|
||||
public static class DirectObjectTestLibrary extends DirectTestLibrary {
|
||||
public DirectObjectTestLibrary(Map options) {
|
||||
Native.register(getClass(), NativeLibrary.getInstance("testlib", options));
|
||||
}
|
||||
}
|
||||
|
||||
public static class DirectNativeMappedLibrary implements NativeMappedLibrary {
|
||||
public native Custom returnInt32Argument(int arg);
|
||||
static {
|
||||
Native.register("testlib");
|
||||
}
|
||||
}
|
||||
protected NativeMappedLibrary loadNativeMappedLibrary() {
|
||||
return new DirectNativeMappedLibrary();
|
||||
}
|
||||
|
||||
// Override not-yet-supported tests
|
||||
public void testReturnObject() { }
|
||||
public void testReturnPointerArray() { }
|
||||
public void testReturnStringArray() { }
|
||||
public void testReturnWStringArray() { }
|
||||
|
||||
public static void main(java.lang.String[] argList) {
|
||||
junit.textui.TestRunner.run(DirectReturnTypesTest.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,527 @@
|
||||
/* Copyright (c) 2009 Timothy Wall, All Rights Reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
* <p/>
|
||||
* This library 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 for more details.
|
||||
*/
|
||||
package com.sun.jna;
|
||||
|
||||
import junit.framework.*;
|
||||
import com.sun.jna.*;
|
||||
import com.sun.jna.ptr.PointerByReference;
|
||||
import java.lang.ref.*;
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
public class DirectTest extends TestCase {
|
||||
|
||||
private static final String BUILDDIR =
|
||||
System.getProperty("jna.builddir",
|
||||
"build" + (Platform.is64Bit() ? "-d64" : ""));
|
||||
|
||||
private static class JNI {
|
||||
static {
|
||||
String path = BUILDDIR + "/native/" + System.mapLibraryName("testlib");;
|
||||
if (!new File(path).isAbsolute()) {
|
||||
path = System.getProperty("user.dir") + "/" + path;
|
||||
}
|
||||
if (path.endsWith(".jnilib")) {
|
||||
path = path.replace(".jnilib", ".dylib");
|
||||
}
|
||||
System.load(path);
|
||||
}
|
||||
|
||||
private static native double cos(double x);
|
||||
}
|
||||
|
||||
public static void main(java.lang.String[] argList) {
|
||||
junit.textui.TestRunner.run(DirectTest.class);
|
||||
checkPerformance();
|
||||
}
|
||||
|
||||
static class MathLibrary {
|
||||
|
||||
public static native double cos(double x);
|
||||
|
||||
static {
|
||||
Native.register(Platform.isWindows()?"msvcrt":"m");
|
||||
}
|
||||
}
|
||||
|
||||
interface MathInterface extends Library {
|
||||
double cos(double x);
|
||||
}
|
||||
|
||||
static class CLibrary {
|
||||
public static class size_t extends IntegerType {
|
||||
public size_t() {
|
||||
super(Native.POINTER_SIZE);
|
||||
}
|
||||
public size_t(long value) {
|
||||
super(Native.POINTER_SIZE, value);
|
||||
}
|
||||
}
|
||||
|
||||
public static native Pointer memset(Pointer p, int v, size_t len);
|
||||
public static native Pointer memset(Pointer p, int v, int len);
|
||||
public static native Pointer memset(Pointer p, int v, long len);
|
||||
public static native long memset(long p, int v, long len);
|
||||
public static native int memset(int p, int v, int len);
|
||||
public static native int strlen(String s1);
|
||||
public static native int strlen(Pointer p);
|
||||
public static native int strlen(byte[] b);
|
||||
public static native int strlen(Buffer b);
|
||||
|
||||
static {
|
||||
Native.register(Platform.isWindows()?"msvcrt":"c");
|
||||
}
|
||||
}
|
||||
|
||||
static interface CInterface extends Library {
|
||||
Pointer memset(Pointer p, int v, int len);
|
||||
int strlen(String s);
|
||||
}
|
||||
|
||||
static interface TestInterface extends Library {
|
||||
interface Int32Callback extends Callback {
|
||||
int invoke(int arg1, int arg2);
|
||||
}
|
||||
interface NativeLongCallback extends Callback {
|
||||
NativeLong invoke(NativeLong arg1, NativeLong arg2);
|
||||
}
|
||||
int callInt32CallbackRepeatedly(Int32Callback cb, int arg1, int arg2, int count);
|
||||
NativeLong callLongCallbackRepeatedly(NativeLongCallback cb, NativeLong arg1, NativeLong arg2, int count);
|
||||
}
|
||||
|
||||
static class TestLibrary implements TestInterface {
|
||||
public native int callInt32CallbackRepeatedly(Int32Callback cb, int arg1, int arg2, int count);
|
||||
public native NativeLong callLongCallbackRepeatedly(NativeLongCallback cb, NativeLong arg1, NativeLong arg2, int count);
|
||||
static {
|
||||
Native.register("testlib");
|
||||
}
|
||||
}
|
||||
|
||||
private static class TestLoader extends URLClassLoader {
|
||||
public TestLoader() throws MalformedURLException {
|
||||
super(new URL[] {
|
||||
new File(BUILDDIR + "/classes").toURI().toURL(),
|
||||
new File(BUILDDIR + "/test-classes").toURI().toURL(),
|
||||
}, null);
|
||||
}
|
||||
}
|
||||
|
||||
public void testRegisterMethods() throws Exception {
|
||||
// Use a dedicated class loader to ensure the class can be gc'd
|
||||
String name = "com.sun.jna.DirectTest$MathLibrary";
|
||||
ClassLoader loader = new TestLoader();
|
||||
Class cls = Class.forName(name, true, loader);
|
||||
assertNotNull("Failed loading class", cls);
|
||||
WeakReference ref = new WeakReference(cls);
|
||||
loader = null;
|
||||
cls = null;
|
||||
System.gc();
|
||||
|
||||
for (int i=0;i < 100 && ref.get() != null;i++) {
|
||||
try {
|
||||
Thread.sleep(10); // Give the GC a chance to run
|
||||
System.gc();
|
||||
} finally {}
|
||||
}
|
||||
// TODO: need a real check to ensure native memory is freed
|
||||
assertNull("Registered methods not GC'd: " + ref.get(), ref.get());
|
||||
}
|
||||
|
||||
private Class returnCallingClass() {
|
||||
return Native.getCallingClass();
|
||||
}
|
||||
|
||||
public void testFindCallingClass() {
|
||||
assertEquals("Wrong calling class detected",
|
||||
getClass(), returnCallingClass());
|
||||
}
|
||||
|
||||
public void testFindNativeClass() {
|
||||
class UnregisterLibrary {
|
||||
class Inner {
|
||||
public Class getNativeClass() {
|
||||
return getNativeClassInner();
|
||||
}
|
||||
public Class getNativeClassInner() {
|
||||
return Native.getNativeClass(Native.getCallingClass());
|
||||
};
|
||||
}
|
||||
public native double cos(double x);
|
||||
public Class getNativeClass() {
|
||||
return new Inner().getNativeClass();
|
||||
};
|
||||
}
|
||||
assertEquals("Wrong native class found",
|
||||
UnregisterLibrary.class, new UnregisterLibrary().getNativeClass());
|
||||
}
|
||||
|
||||
// Requires java.library.path include testlib
|
||||
public static void checkPerformance() {
|
||||
final int COUNT = 100000;
|
||||
System.out.println("Checking performance of different access methods (" + COUNT + " iterations)");
|
||||
final int SIZE = 8*1024;
|
||||
ByteBuffer b = ByteBuffer.allocateDirect(SIZE);
|
||||
// Native order is faster
|
||||
b.order(ByteOrder.nativeOrder());
|
||||
Pointer pb = Native.getDirectBufferPointer(b);
|
||||
|
||||
String mname = Platform.isWindows()?"msvcrt":"m";
|
||||
MathInterface mlib = (MathInterface)
|
||||
Native.loadLibrary(mname, MathInterface.class);
|
||||
Function f = NativeLibrary.getInstance(mname).getFunction("cos");
|
||||
|
||||
///////////////////////////////////////////
|
||||
// cos
|
||||
Object[] args = { new Double(0) };
|
||||
double dresult;
|
||||
long start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
dresult = mlib.cos(0d);
|
||||
}
|
||||
long delta = System.currentTimeMillis() - start;
|
||||
System.out.println("cos (JNA interface): " + delta + "ms");
|
||||
|
||||
start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
dresult = f.invokeDouble(args);
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
System.out.println("cos (JNA function): " + delta + "ms");
|
||||
|
||||
start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
dresult = MathLibrary.cos(0d);
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
System.out.println("cos (JNA direct): " + delta + "ms");
|
||||
|
||||
long types = pb.peer;
|
||||
long cif;
|
||||
long resp;
|
||||
long argv;
|
||||
if (Native.POINTER_SIZE == 4) {
|
||||
b.putInt(0, (int)Structure.FFIType.get(double.class).peer);
|
||||
cif = Native.ffi_prep_cif(0, 1, Structure.FFIType.get(double.class).peer, types);
|
||||
resp = pb.peer + 4;
|
||||
argv = pb.peer + 12;
|
||||
double INPUT = 42;
|
||||
start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
b.putInt(12, (int)pb.peer + 16);
|
||||
b.putDouble(16, INPUT);
|
||||
Native.ffi_call(cif, f.peer, resp, argv);
|
||||
dresult = b.getDouble(4);
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
}
|
||||
else {
|
||||
b.putLong(0, Structure.FFIType.get(double.class).peer);
|
||||
cif = Native.ffi_prep_cif(0, 1, Structure.FFIType.get(double.class).peer, types);
|
||||
resp = pb.peer + 8;
|
||||
argv = pb.peer + 16;
|
||||
double INPUT = 42;
|
||||
start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
b.putLong(16, pb.peer + 24);
|
||||
b.putDouble(24, INPUT);
|
||||
Native.ffi_call(cif, f.peer, resp, argv);
|
||||
dresult = b.getDouble(8);
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
}
|
||||
System.out.println("cos (JNI ffi): " + delta + "ms");
|
||||
|
||||
start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
dresult = JNI.cos(0d);
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
System.out.println("cos (JNI): " + delta + "ms");
|
||||
|
||||
start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
dresult = Math.cos(0d);
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
System.out.println("cos (pure java): " + delta + "ms");
|
||||
|
||||
///////////////////////////////////////////
|
||||
// memset
|
||||
Pointer presult;
|
||||
String cname = Platform.isWindows()?"msvcrt":"c";
|
||||
CInterface clib = (CInterface)
|
||||
Native.loadLibrary(cname, CInterface.class);
|
||||
start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
presult = clib.memset(null, 0, 0);
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
System.out.println("memset (JNA interface): " + delta + "ms");
|
||||
|
||||
f = NativeLibrary.getInstance(cname).getFunction("memset");
|
||||
args = new Object[] { null, new Integer(0), new Integer(0)};
|
||||
start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
presult = f.invokePointer(args);
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
System.out.println("memset (JNA function): " + delta + "ms");
|
||||
|
||||
start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
presult = CLibrary.memset((Pointer)null, 0, new CLibrary.size_t(0));
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
System.out.println("memset (JNA direct Pointer/size_t): " + delta + "ms");
|
||||
start = System.currentTimeMillis();
|
||||
if (Native.POINTER_SIZE == 4) {
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
presult = CLibrary.memset((Pointer)null, 0, 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
presult = CLibrary.memset((Pointer)null, 0, 0L);
|
||||
}
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
System.out.println("memset (JNA direct Pointer/primitive): " + delta + "ms");
|
||||
int iresult;
|
||||
long jresult;
|
||||
start = System.currentTimeMillis();
|
||||
if (Native.POINTER_SIZE == 4) {
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
iresult = CLibrary.memset(0, 0, 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
jresult = CLibrary.memset(0L, 0, 0L);
|
||||
}
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
System.out.println("memset (JNA direct primitives): " + delta + "ms");
|
||||
|
||||
if (Native.POINTER_SIZE == 4) {
|
||||
b.putInt(0, (int)Structure.FFIType.get(Pointer.class).peer);
|
||||
b.putInt(4, (int)Structure.FFIType.get(int.class).peer);
|
||||
b.putInt(8, (int)Structure.FFIType.get(int.class).peer);
|
||||
cif = Native.ffi_prep_cif(0, 3, Structure.FFIType.get(Pointer.class).peer, types);
|
||||
resp = pb.peer + 12;
|
||||
argv = pb.peer + 16;
|
||||
start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
b.putInt(16, (int)pb.peer + 28);
|
||||
b.putInt(20, (int)pb.peer + 32);
|
||||
b.putInt(24, (int)pb.peer + 36);
|
||||
b.putInt(28, 0);
|
||||
b.putInt(32, 0);
|
||||
b.putInt(36, 0);
|
||||
Native.ffi_call(cif, f.peer, resp, argv);
|
||||
b.getInt(12);
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
}
|
||||
else {
|
||||
b.putLong(0, Structure.FFIType.get(Pointer.class).peer);
|
||||
b.putLong(8, Structure.FFIType.get(int.class).peer);
|
||||
b.putLong(16, Structure.FFIType.get(long.class).peer);
|
||||
cif = Native.ffi_prep_cif(0, 3, Structure.FFIType.get(Pointer.class).peer, types);
|
||||
resp = pb.peer + 24;
|
||||
argv = pb.peer + 32;
|
||||
start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
b.putLong(32, pb.peer + 56);
|
||||
b.putLong(40, pb.peer + 64);
|
||||
b.putLong(48, pb.peer + 72);
|
||||
b.putLong(56, 0);
|
||||
b.putInt(64, 0);
|
||||
b.putLong(72, 0);
|
||||
Native.ffi_call(cif, f.peer, resp, argv);
|
||||
b.getLong(24);
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
}
|
||||
System.out.println("memset (JNI ffi): " + delta + "ms");
|
||||
|
||||
start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
Pointer._setMemory(0L, 0L, (byte)0);
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
System.out.println("memset (JNI): " + delta + "ms");
|
||||
|
||||
///////////////////////////////////////////
|
||||
// strlen
|
||||
String str = "performance test";
|
||||
start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
iresult = clib.strlen(str);
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
System.out.println("strlen (JNA interface): " + delta + "ms");
|
||||
|
||||
f = NativeLibrary.getInstance(cname).getFunction("strlen");
|
||||
args = new Object[] { str };
|
||||
start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
iresult = f.invokeInt(args);
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
System.out.println("strlen (JNA function): " + delta + "ms");
|
||||
|
||||
start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
iresult = CLibrary.strlen(str);
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
System.out.println("strlen (JNA direct - String): " + delta + "ms");
|
||||
|
||||
start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
iresult = CLibrary.strlen(new NativeString(str).getPointer());
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
System.out.println("strlen (JNA direct - Pointer): " + delta + "ms");
|
||||
|
||||
start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
iresult = CLibrary.strlen(Native.toByteArray(str));
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
System.out.println("strlen (JNA direct - byte[]): " + delta + "ms");
|
||||
|
||||
start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
byte[] bytes = str.getBytes();
|
||||
b.position(0);
|
||||
b.put(bytes);
|
||||
b.put((byte)0);
|
||||
iresult = CLibrary.strlen(b);
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
System.out.println("strlen (JNA direct - Buffer): " + delta + "ms");
|
||||
|
||||
if (Native.POINTER_SIZE == 4) {
|
||||
b.putInt(0, (int)Structure.FFIType.get(Pointer.class).peer);
|
||||
cif = Native.ffi_prep_cif(0, 1, Structure.FFIType.get(int.class).peer, types);
|
||||
resp = pb.peer + 4;
|
||||
argv = pb.peer + 8;
|
||||
start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
b.putInt(8, (int)pb.peer + 12);
|
||||
b.putInt(12, (int)pb.peer + 16);
|
||||
b.position(16);
|
||||
// This operation is very expensive!
|
||||
b.put(str.getBytes());
|
||||
b.put((byte)0);
|
||||
Native.ffi_call(cif, f.peer, resp, argv);
|
||||
iresult = b.getInt(4);
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
}
|
||||
else {
|
||||
b.putLong(0, Structure.FFIType.get(Pointer.class).peer);
|
||||
cif = Native.ffi_prep_cif(0, 1, Structure.FFIType.get(long.class).peer, types);
|
||||
resp = pb.peer + 8;
|
||||
argv = pb.peer + 16;
|
||||
start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
b.putLong(16, pb.peer + 24);
|
||||
b.putLong(24, pb.peer + 32);
|
||||
b.position(32);
|
||||
// This operation is very expensive!
|
||||
b.put(str.getBytes());
|
||||
b.put((byte)0);
|
||||
Native.ffi_call(cif, f.peer, resp, argv);
|
||||
jresult = b.getLong(8);
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
}
|
||||
System.out.println("strlen (JNI ffi): " + delta + "ms");
|
||||
|
||||
///////////////////////////////////////////
|
||||
// Direct buffer vs. Pointer methods
|
||||
byte[] bulk = new byte[SIZE];
|
||||
start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
b.putInt(0, 0);
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
System.out.println("direct Buffer write: " + delta + "ms");
|
||||
|
||||
start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
b.position(0);
|
||||
b.put(bulk);
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
System.out.println("direct Buffer write (bulk): " + delta + "ms");
|
||||
|
||||
Pointer p = new Memory(SIZE);
|
||||
start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
p.setInt(0, 0);
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
System.out.println("Memory write: " + delta + "ms");
|
||||
|
||||
start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
p.write(0, bulk, 0, bulk.length);
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
System.out.println("Memory write (bulk): " + delta + "ms");
|
||||
|
||||
///////////////////////////////////////////
|
||||
// Callbacks
|
||||
TestInterface tlib = (TestInterface)Native.loadLibrary("testlib", TestInterface.class);
|
||||
start = System.currentTimeMillis();
|
||||
TestInterface.Int32Callback cb = new TestInterface.Int32Callback() {
|
||||
public int invoke(int arg1, int arg2) {
|
||||
return arg1 + arg2;
|
||||
}
|
||||
};
|
||||
tlib.callInt32CallbackRepeatedly(cb, 1, 2, COUNT);
|
||||
delta = System.currentTimeMillis() - start;
|
||||
System.out.println("callback (JNA interface): " + delta + "ms");
|
||||
|
||||
tlib = new TestLibrary();
|
||||
start = System.currentTimeMillis();
|
||||
tlib.callInt32CallbackRepeatedly(cb, 1, 2, COUNT);
|
||||
delta = System.currentTimeMillis() - start;
|
||||
System.out.println("callback (JNA direct): " + delta + "ms");
|
||||
|
||||
start = System.currentTimeMillis();
|
||||
TestInterface.NativeLongCallback nlcb = new TestInterface.NativeLongCallback() {
|
||||
public NativeLong invoke(NativeLong arg1, NativeLong arg2) {
|
||||
return new NativeLong(arg1.longValue() + arg2.longValue());
|
||||
}
|
||||
};
|
||||
tlib.callLongCallbackRepeatedly(nlcb, new NativeLong(1), new NativeLong(2), COUNT);
|
||||
delta = System.currentTimeMillis() - start;
|
||||
System.out.println("callback w/NativeMapped (JNA interface): " + delta + "ms");
|
||||
|
||||
tlib = new TestLibrary();
|
||||
start = System.currentTimeMillis();
|
||||
tlib.callLongCallbackRepeatedly(nlcb, new NativeLong(1), new NativeLong(2), COUNT);
|
||||
delta = System.currentTimeMillis() - start;
|
||||
System.out.println("callback w/NativeMapped (JNA direct): " + delta + "ms");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
/* Copyright (c) 2009 Timothy Wall, All Rights Reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
* <p/>
|
||||
* This library 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 for more details.
|
||||
*/
|
||||
|
||||
package com.sun.jna;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class DirectTypeMapperTest extends TestCase {
|
||||
|
||||
public static class DirectTestLibraryBoolean {
|
||||
final static int MAGIC = 0xABEDCF23;
|
||||
public native int returnInt32Argument(boolean b);
|
||||
static {
|
||||
Map options = new HashMap();
|
||||
DefaultTypeMapper mapper = new DefaultTypeMapper();
|
||||
mapper.addToNativeConverter(Boolean.class, new ToNativeConverter() {
|
||||
public Object toNative(Object arg, ToNativeContext ctx) {
|
||||
return new Integer(Boolean.TRUE.equals(arg) ? MAGIC : 0);
|
||||
}
|
||||
public Class nativeType() {
|
||||
return Integer.class;
|
||||
}
|
||||
});
|
||||
options.put(Library.OPTION_TYPE_MAPPER, mapper);
|
||||
Native.register(NativeLibrary.getInstance("testlib", options));
|
||||
}
|
||||
}
|
||||
public static class DirectTestLibraryString {
|
||||
public native int returnInt32Argument(String s);
|
||||
static {
|
||||
DefaultTypeMapper mapper = new DefaultTypeMapper();
|
||||
mapper.addToNativeConverter(String.class, new ToNativeConverter() {
|
||||
public Object toNative(Object arg, ToNativeContext ctx) {
|
||||
return Integer.valueOf((String) arg, 16);
|
||||
}
|
||||
public Class nativeType() {
|
||||
return Integer.class;
|
||||
}
|
||||
});
|
||||
Map options = new HashMap();
|
||||
options.put(Library.OPTION_TYPE_MAPPER, mapper);
|
||||
Native.register(NativeLibrary.getInstance("testlib", options));
|
||||
}
|
||||
}
|
||||
public static class DirectTestLibraryCharSequence {
|
||||
public native int returnInt32Argument(String n);
|
||||
static {
|
||||
DefaultTypeMapper mapper = new DefaultTypeMapper();
|
||||
mapper.addToNativeConverter(CharSequence.class, new ToNativeConverter() {
|
||||
public Object toNative(Object arg, ToNativeContext ctx) {
|
||||
return Integer.valueOf(((CharSequence)arg).toString(), 16);
|
||||
}
|
||||
public Class nativeType() {
|
||||
return Integer.class;
|
||||
}
|
||||
});
|
||||
Map options = new HashMap();
|
||||
options.put(Library.OPTION_TYPE_MAPPER, mapper);
|
||||
|
||||
Native.register(NativeLibrary.getInstance("testlib", options));
|
||||
}
|
||||
}
|
||||
public static class DirectTestLibraryNumber {
|
||||
public native int returnInt32Argument(Number n);
|
||||
static {
|
||||
DefaultTypeMapper mapper = new DefaultTypeMapper();
|
||||
mapper.addToNativeConverter(Number.class, new ToNativeConverter() {
|
||||
public Object toNative(Object arg, ToNativeContext ctx) {
|
||||
return new Integer(((Number)arg).intValue());
|
||||
}
|
||||
public Class nativeType() {
|
||||
return Integer.class;
|
||||
}
|
||||
});
|
||||
Map options = new HashMap();
|
||||
options.put(Library.OPTION_TYPE_MAPPER, mapper);
|
||||
|
||||
Native.register(NativeLibrary.getInstance("testlib", options));
|
||||
}
|
||||
}
|
||||
|
||||
public void testBooleanToIntArgumentConversion() {
|
||||
DirectTestLibraryBoolean lib = new DirectTestLibraryBoolean();
|
||||
assertEquals("Failed to convert Boolean argument to Int",
|
||||
lib.MAGIC,
|
||||
lib.returnInt32Argument(true));
|
||||
}
|
||||
public void testStringToIntArgumentConversion() {
|
||||
final int MAGIC = 0x7BEDCF23;
|
||||
DirectTestLibraryString lib = new DirectTestLibraryString();
|
||||
assertEquals("Failed to convert String argument to Int", MAGIC,
|
||||
lib.returnInt32Argument(Integer.toHexString(MAGIC)));
|
||||
}
|
||||
public void testCharSequenceToIntArgumentConversion() {
|
||||
final int MAGIC = 0x7BEDCF23;
|
||||
DirectTestLibraryCharSequence lib = new DirectTestLibraryCharSequence();
|
||||
assertEquals("Failed to convert String argument to Int", MAGIC,
|
||||
lib.returnInt32Argument(Integer.toHexString(MAGIC)));
|
||||
}
|
||||
public void testNumberToIntArgumentConversion() {
|
||||
|
||||
final int MAGIC = 0x7BEDCF23;
|
||||
DirectTestLibraryNumber lib = new DirectTestLibraryNumber();
|
||||
assertEquals("Failed to convert Double argument to Int", MAGIC,
|
||||
lib.returnInt32Argument(new Double(MAGIC)));
|
||||
}
|
||||
public static class DirectBooleanTestLibrary {
|
||||
public native boolean returnInt32Argument(boolean b);
|
||||
static {
|
||||
final int MAGIC = 0xABEDCF23;
|
||||
Map options = new HashMap();
|
||||
DefaultTypeMapper mapper = new DefaultTypeMapper();
|
||||
// Use opposite sense of default int<-->boolean conversions
|
||||
mapper.addToNativeConverter(Boolean.class, new ToNativeConverter() {
|
||||
public Object toNative(Object value, ToNativeContext ctx) {
|
||||
return new Integer(Boolean.TRUE.equals(value) ? 0 : MAGIC);
|
||||
}
|
||||
public Class nativeType() {
|
||||
return Integer.class;
|
||||
}
|
||||
});
|
||||
mapper.addFromNativeConverter(Boolean.class, new FromNativeConverter() {
|
||||
public Object fromNative(Object value, FromNativeContext context) {
|
||||
return Boolean.valueOf(((Integer) value).intValue() != MAGIC);
|
||||
}
|
||||
public Class nativeType() {
|
||||
return Integer.class;
|
||||
}
|
||||
});
|
||||
options.put(Library.OPTION_TYPE_MAPPER, mapper);
|
||||
Native.register(NativeLibrary.getInstance("testlib", options));
|
||||
}
|
||||
}
|
||||
public void testIntegerToBooleanResultConversion() throws Exception {
|
||||
DirectBooleanTestLibrary lib = new DirectBooleanTestLibrary();
|
||||
// argument "true" converts to zero; result zero converts to "true"
|
||||
assertTrue("Failed to convert integer return to boolean TRUE",
|
||||
lib.returnInt32Argument(true));
|
||||
// argument "true" converts to MAGIC; result MAGIC converts to "false"
|
||||
assertFalse("Failed to convert integer return to boolean FALSE",
|
||||
lib.returnInt32Argument(false));
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
junit.textui.TestRunner.run(DirectTypeMapperTest.class);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2007 Timothy Wall, All Rights Reserved
|
||||
/* Copyright (c) 2007-2009 Timothy Wall, All Rights Reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -12,41 +12,138 @@
|
||||
*/
|
||||
package com.sun.jna;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.io.File;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class JNAUnloadTest extends TestCase {
|
||||
|
||||
private static final String BUILDDIR =
|
||||
System.getProperty("jna.builddir", "build"
|
||||
+ (Native.POINTER_SIZE == 8 ? "-d64" : ""));
|
||||
+ (Platform.is64Bit() ? "-d64" : ""));
|
||||
|
||||
private static class TestLoader extends URLClassLoader {
|
||||
public TestLoader() throws MalformedURLException {
|
||||
public TestLoader(boolean fromJar) throws MalformedURLException {
|
||||
super(new URL[] {
|
||||
new File(BUILDDIR + "/classes").toURI().toURL(),
|
||||
new File(BUILDDIR + (fromJar ? "/jna.jar" : "/classes")).toURI().toURL(),
|
||||
}, null);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: test auto-dispose of callback memory
|
||||
// Fails under clover
|
||||
public void testUnloadFromJar() throws Exception {
|
||||
File jar = new File(BUILDDIR + "/jna.jar");
|
||||
assertTrue("Expected JNA jar file at " + jar + " is missing", jar.exists());
|
||||
|
||||
public void testUnload() throws Exception {
|
||||
ClassLoader loader = new TestLoader();
|
||||
ClassLoader loader = new TestLoader(true);
|
||||
Class cls = Class.forName("com.sun.jna.Native", true, loader);
|
||||
assertEquals("Wrong class loader", loader, cls.getClassLoader());
|
||||
|
||||
Field field = cls.getDeclaredField("nativeLibraryPath");
|
||||
field.setAccessible(true);
|
||||
String path = (String)field.get(null);
|
||||
assertTrue("Native library not unpacked from jar: " + path,
|
||||
path.startsWith(System.getProperty("java.io.tmpdir")));
|
||||
|
||||
WeakReference ref = new WeakReference(cls);
|
||||
WeakReference clref = new WeakReference(loader);
|
||||
loader = null;
|
||||
cls = null;
|
||||
field = null;
|
||||
System.gc();
|
||||
for (int i=0;i < 100 && (ref.get() != null || clref.get() != null);i++) {
|
||||
Thread.sleep(10);
|
||||
System.gc();
|
||||
}
|
||||
assertNull("Class not GC'd: " + ref.get(), ref.get());
|
||||
assertNull("ClassLoader not GC'd: " + clref.get(), clref.get());
|
||||
File f = new File(path);
|
||||
for (int i=0;i < 100 && f.exists();i++) {
|
||||
Thread.sleep(10);
|
||||
System.gc();
|
||||
}
|
||||
// NOTE: Temporary file removal on Windows only works on a Sun VM
|
||||
try {
|
||||
if (Platform.isWindows()) {
|
||||
ClassLoader.class.getDeclaredField("nativeLibraries");
|
||||
}
|
||||
if (f.exists() && !f.delete()) {
|
||||
assertFalse("Temporary native library still locked: " + path,
|
||||
f.exists());
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
// Skip on non-supported VMs
|
||||
}
|
||||
|
||||
try {
|
||||
loader = new TestLoader(true);
|
||||
cls = Class.forName("com.sun.jna.Native", true, loader);
|
||||
}
|
||||
catch(Throwable t) {
|
||||
fail("Native library not unloaded: " + t.getMessage());
|
||||
}
|
||||
finally {
|
||||
loader = null;
|
||||
cls = null;
|
||||
System.gc();
|
||||
}
|
||||
}
|
||||
|
||||
// Fails under clover
|
||||
public void testUnload() throws Exception {
|
||||
ClassLoader loader = new TestLoader(false);
|
||||
Class cls = Class.forName("com.sun.jna.Native", true, loader);
|
||||
assertEquals("Wrong class loader", loader, cls.getClassLoader());
|
||||
|
||||
Field field = cls.getDeclaredField("nativeLibraryPath");
|
||||
field.setAccessible(true);
|
||||
String path = (String)field.get(null);
|
||||
assertNotNull("Native library not found", path);
|
||||
|
||||
WeakReference ref = new WeakReference(cls);
|
||||
WeakReference clref = new WeakReference(loader);
|
||||
loader = null;
|
||||
cls = null;
|
||||
field = null;
|
||||
System.gc();
|
||||
for (int i=0;i < 100 && (ref.get() != null || clref.get() != null);i++) {
|
||||
Thread.sleep(10);
|
||||
System.gc();
|
||||
}
|
||||
assertNull("Class not GC'd: " + ref.get(), ref.get());
|
||||
assertNull("ClassLoader not GC'd: " + clref.get(), clref.get());
|
||||
|
||||
Throwable throwable = null;
|
||||
// NOTE: IBM J9 needs some extra time to unload the native library,
|
||||
// so try a few times before failing
|
||||
for (int i=0;i < 100;i++) {
|
||||
System.gc();
|
||||
Thread.sleep(10);
|
||||
try {
|
||||
loader = new TestLoader(false);
|
||||
cls = Class.forName("com.sun.jna.Native", true, loader);
|
||||
break;
|
||||
}
|
||||
catch(Throwable t) {
|
||||
loader = null;
|
||||
throwable = t;
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (loader == null)
|
||||
fail("Native library not unloaded: " + throwable.getMessage());
|
||||
}
|
||||
finally {
|
||||
loader = null;
|
||||
cls = null;
|
||||
System.gc();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/* Copyright (c) 2009 Timothy Wall, All Rights Reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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 for more details.
|
||||
*/
|
||||
package com.sun.jna;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class LastErrorTest extends TestCase {
|
||||
|
||||
private static final Map OPTIONS = new HashMap() {{
|
||||
put(Library.OPTION_FUNCTION_MAPPER, new FunctionMapper() {
|
||||
public String getFunctionName(NativeLibrary library, Method m) {
|
||||
if (m.getName().equals("noThrowLastError")
|
||||
|| m.getName().equals("throwLastError")) {
|
||||
return "setLastError";
|
||||
}
|
||||
return m.getName();
|
||||
}
|
||||
});
|
||||
}};
|
||||
|
||||
public interface TestLibrary extends Library {
|
||||
void noThrowLastError(int code);
|
||||
void throwLastError(int code) throws LastErrorException;
|
||||
}
|
||||
|
||||
public static class DirectTestLibrary implements TestLibrary {
|
||||
public native void noThrowLastError(int code);
|
||||
public native void throwLastError(int code) throws LastErrorException;
|
||||
static {
|
||||
Native.register(NativeLibrary.getInstance("testlib", OPTIONS));
|
||||
}
|
||||
}
|
||||
|
||||
public void testThrowLastError() {
|
||||
Map options = new HashMap();
|
||||
TestLibrary lib = (TestLibrary)Native.loadLibrary("testlib", TestLibrary.class, OPTIONS);
|
||||
|
||||
final int ERROR = -1;
|
||||
lib.noThrowLastError(ERROR);
|
||||
assertEquals("Last error not preserved", ERROR, Native.getLastError());
|
||||
try {
|
||||
lib.throwLastError(ERROR);
|
||||
fail("Method should throw LastErrorException");
|
||||
}
|
||||
catch(LastErrorException e) {
|
||||
assertEquals("Exception should contain error code", ERROR, e.errorCode);
|
||||
}
|
||||
}
|
||||
|
||||
public void testThrowLastErrorDirect() {
|
||||
TestLibrary lib = new DirectTestLibrary();
|
||||
|
||||
final int ERROR = -1;
|
||||
lib.noThrowLastError(ERROR);
|
||||
assertEquals("Last error not preserved", ERROR, Native.getLastError());
|
||||
try {
|
||||
lib.throwLastError(ERROR);
|
||||
fail("Method should throw LastErrorException");
|
||||
}
|
||||
catch(LastErrorException e) {
|
||||
assertEquals("Exception should contain error code", ERROR, e.errorCode);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
junit.textui.TestRunner.run(LastErrorTest.class);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2007 Timothy Wall, All Rights Reserved
|
||||
/* Copyright (c) 2007-2009 Timothy Wall, All Rights Reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -13,8 +13,8 @@
|
||||
package com.sun.jna;
|
||||
|
||||
import java.awt.Frame;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Toolkit;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
@@ -26,7 +26,7 @@ public class LibraryLoadTest extends TestCase {
|
||||
|
||||
private static final String BUILDDIR =
|
||||
System.getProperty("jna.builddir", "build"
|
||||
+ (Native.POINTER_SIZE == 8 ? "-d64" : ""));
|
||||
+ (Platform.is64Bit() ? "-d64" : ""));
|
||||
|
||||
public void testLoadJNALibrary() {
|
||||
assertTrue("Point size should never be zero", Pointer.SIZE > 0);
|
||||
@@ -54,6 +54,8 @@ public class LibraryLoadTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testLoadAWTAfterJNA() {
|
||||
if (GraphicsEnvironment.isHeadless()) return;
|
||||
|
||||
if (Pointer.SIZE > 0) {
|
||||
Toolkit.getDefaultToolkit();
|
||||
}
|
||||
@@ -89,6 +91,8 @@ public class LibraryLoadTest extends TestCase {
|
||||
String tmp = System.getProperty("java.io.tmpdir");
|
||||
String libName = System.mapLibraryName("jnidispatch");
|
||||
File src = new File(BUILDDIR + "/native", libName);
|
||||
assertTrue("Expected JNA native library at " + src + " is missing", src.exists());
|
||||
|
||||
String newLibName = UNICODE;
|
||||
if (libName.startsWith("lib"))
|
||||
newLibName = "lib" + newLibName;
|
||||
@@ -105,7 +109,8 @@ public class LibraryLoadTest extends TestCase {
|
||||
dst.deleteOnExit();
|
||||
copy(src, dst);
|
||||
NativeLibrary.addSearchPath(UNICODE, tmp);
|
||||
NativeLibrary.getInstance(UNICODE);
|
||||
NativeLibrary nl = NativeLibrary.getInstance(UNICODE);
|
||||
nl.dispose();
|
||||
}
|
||||
|
||||
public void testHandleObjectMethods() {
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
package com.sun.jna;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class MemoryTest extends TestCase {
|
||||
@@ -31,9 +34,10 @@ public class MemoryTest extends TestCase {
|
||||
System.gc();
|
||||
long start = System.currentTimeMillis();
|
||||
assertFalse("Memory prematurely GC'd", flag[0]);
|
||||
// This check fails on IBM's J9, on which the weak ref
|
||||
// is cleared but the object not yet GC'd
|
||||
//assertNotNull("Memory prematurely GC'd", ref.get());
|
||||
assertNotNull("Base memory GC'd while shared memory extant", ref.get());
|
||||
// Avoid having IBM J9 prematurely nullify "shared"
|
||||
shared.setInt(0, 0);
|
||||
|
||||
shared = null;
|
||||
System.gc();
|
||||
while (ref.get() != null) {
|
||||
@@ -64,17 +68,25 @@ public class MemoryTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testAlignment() {
|
||||
final int SIZE = 128;
|
||||
final int SIZE = 1<<16;
|
||||
Memory base = new Memory(SIZE);
|
||||
for (int align=1;align < 8;align *= 2) {
|
||||
for (int align=1;align < SIZE;align *= 2) {
|
||||
Memory unaligned = base;
|
||||
long mask = ~((long)align - 1);
|
||||
if ((base.peer & mask) == base.peer)
|
||||
unaligned = (Memory)base.share(1, SIZE-1);
|
||||
Pointer aligned = unaligned.align(align);
|
||||
assertEquals("Memory not aligned",
|
||||
assertEquals("Memory not aligned (" + align + ")",
|
||||
aligned.peer & mask, aligned.peer);
|
||||
|
||||
assertSame("Alignment request on aligned memory should no-op",
|
||||
aligned, ((Memory)aligned).align(align));
|
||||
}
|
||||
}
|
||||
|
||||
public void testNegativeAlignment() {
|
||||
final int SIZE = 128;
|
||||
Memory base = new Memory(SIZE);
|
||||
try {
|
||||
base.align(-1);
|
||||
fail("Negative alignments not allowed");
|
||||
@@ -82,6 +94,49 @@ public class MemoryTest extends TestCase {
|
||||
catch(IllegalArgumentException e) { }
|
||||
}
|
||||
|
||||
public void testInvalidAlignment() {
|
||||
final int SIZE = 128;
|
||||
Memory base = new Memory(SIZE);
|
||||
int[] alignments = { 0, 3, 5, 9, 13 };
|
||||
for (int i=0;i < alignments.length;i++) {
|
||||
try {
|
||||
base.align(alignments[i]);
|
||||
fail("Power-of-two alignments required");
|
||||
}
|
||||
catch(IllegalArgumentException e) { }
|
||||
}
|
||||
}
|
||||
|
||||
public void testAvoidGCWithExtantBuffer() throws Exception {
|
||||
Memory m = new Memory(1024);
|
||||
ByteBuffer b = m.getByteBuffer(0, m.getSize());
|
||||
WeakReference ref = new WeakReference(m);
|
||||
WeakReference bref = new WeakReference(b);
|
||||
m = null;
|
||||
System.gc();
|
||||
Memory.purge();
|
||||
for (int i=0;i < 100 && ref.get() != null;i++) {
|
||||
Thread.sleep(10);
|
||||
System.gc();
|
||||
Memory.purge();
|
||||
}
|
||||
assertNotNull("Memory GC'd while NIO Buffer still extant", ref.get());
|
||||
|
||||
// Avoid IBM J9 optimization resulting in premature GC of buffer
|
||||
b.put((byte)0);
|
||||
|
||||
b = null;
|
||||
System.gc();
|
||||
Memory.purge();
|
||||
for (int i=0;i < 100 && (bref.get() != null || ref.get() != null);i++) {
|
||||
Thread.sleep(10);
|
||||
System.gc();
|
||||
Memory.purge();
|
||||
}
|
||||
assertNull("Buffer not GC'd\n", bref.get());
|
||||
assertNull("Memory not GC'd after buffer GC'd\n", ref.get());
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
junit.textui.TestRunner.run(MemoryTest.class);
|
||||
}
|
||||
|
||||
@@ -182,6 +182,12 @@ public class NativeLibraryTest extends TestCase {
|
||||
}
|
||||
}
|
||||
|
||||
public void testGetProcess() {
|
||||
NativeLibrary process = NativeLibrary.getProcess();
|
||||
// Access a common C library function
|
||||
process.getFunction("printf");
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
junit.textui.TestRunner.run(NativeLibraryTest.class);
|
||||
}
|
||||
|
||||
@@ -194,8 +194,103 @@ public class NativeTest extends TestCase {
|
||||
Native.getStructureAlignment(TestInterfaceWithAlignment.class));
|
||||
}
|
||||
|
||||
// TODO extract (alignment|typemapper)
|
||||
// from (variable|options)
|
||||
public void testCharArrayToString() {
|
||||
char[] buf = { 'a', 'b', 'c', '\0', 'd', 'e' };
|
||||
assertEquals("Wrong String generated", "abc", Native.toString(buf));
|
||||
}
|
||||
|
||||
public void testByteArrayToString() {
|
||||
byte[] buf = { 'a', 'b', 'c', '\0', 'd', 'e' };
|
||||
assertEquals("Wrong String generated", "abc", Native.toString(buf));
|
||||
}
|
||||
|
||||
public void testToByteArray() {
|
||||
final String VALUE = getName();
|
||||
byte[] buf = Native.toByteArray(VALUE);
|
||||
assertEquals("Wrong byte array length", VALUE.length()+1, buf.length);
|
||||
assertEquals("Missing NUL terminator", (byte)0, buf[buf.length-1]);
|
||||
assertEquals("Wrong byte array contents", VALUE, new String(buf, 0, buf.length-1));
|
||||
}
|
||||
|
||||
public void testToCharArray() {
|
||||
final String VALUE = getName();
|
||||
char[] buf = Native.toCharArray(VALUE);
|
||||
assertEquals("Wrong char array length", VALUE.length()+1, buf.length);
|
||||
assertEquals("Missing NUL terminator", (char)0, buf[buf.length-1]);
|
||||
assertEquals("Wrong char array contents: " + new String(buf), VALUE, new String(buf, 0, buf.length-1));
|
||||
}
|
||||
|
||||
public void testOSPrefix() {
|
||||
assertEquals("Wrong resource path", "/com/sun/jna/win32-x86",
|
||||
Native.getNativeLibraryResourcePath(Platform.WINDOWS,
|
||||
"x86", "Windows"));
|
||||
assertEquals("Wrong resource path Windows/i386", "/com/sun/jna/win32-x86",
|
||||
Native.getNativeLibraryResourcePath(Platform.WINDOWS,
|
||||
"i386", "Windows"));
|
||||
assertEquals("Wrong resource path Mac/x86", "/com/sun/jna/darwin",
|
||||
Native.getNativeLibraryResourcePath(Platform.MAC,
|
||||
"x86", "Darwin"));
|
||||
assertEquals("Wrong resource path Mac/x86_64", "/com/sun/jna/darwin",
|
||||
Native.getNativeLibraryResourcePath(Platform.MAC,
|
||||
"x86_64", "Mac"));
|
||||
assertEquals("Wrong resource path Solaris/sparc", "/com/sun/jna/sunos-sparc",
|
||||
Native.getNativeLibraryResourcePath(Platform.SOLARIS,
|
||||
"sparc", "Solaris"));
|
||||
assertEquals("Wrong resource path SunOS/sparcv9", "/com/sun/jna/sunos-sparcv9",
|
||||
Native.getNativeLibraryResourcePath(Platform.SOLARIS,
|
||||
"sparcv9", "SunOS"));
|
||||
assertEquals("Wrong resource path Linux/i386", "/com/sun/jna/linux-i386",
|
||||
Native.getNativeLibraryResourcePath(Platform.LINUX,
|
||||
"i386", "Linux/Gnu"));
|
||||
assertEquals("Wrong resource path Linux/x86", "/com/sun/jna/linux-i386",
|
||||
Native.getNativeLibraryResourcePath(Platform.LINUX,
|
||||
"x86", "Linux"));
|
||||
assertEquals("Wrong resource path OpenBSD/x86", "/com/sun/jna/openbsd-i386",
|
||||
Native.getNativeLibraryResourcePath(Platform.OPENBSD,
|
||||
"x86", "OpenBSD"));
|
||||
assertEquals("Wrong resource path FreeBSD/x86", "/com/sun/jna/freebsd-i386",
|
||||
Native.getNativeLibraryResourcePath(Platform.FREEBSD,
|
||||
"x86", "FreeBSD"));
|
||||
assertEquals("Wrong resource path other/other", "/com/sun/jna/name-ppc",
|
||||
Native.getNativeLibraryResourcePath(Platform.UNSPECIFIED,
|
||||
"PowerPC", "Name Of System"));
|
||||
|
||||
}
|
||||
|
||||
public static class DirectMapping {
|
||||
public static class DirectStructure extends Structure {
|
||||
public int field;
|
||||
}
|
||||
public static interface DirectCallback extends Callback {
|
||||
void invoke();
|
||||
}
|
||||
public DirectMapping(Map options) {
|
||||
Native.register(getClass(), NativeLibrary.getInstance("testlib", options));
|
||||
}
|
||||
}
|
||||
|
||||
public void testGetTypeMapperForDirectMapping() {
|
||||
final TypeMapper mapper = new DefaultTypeMapper();
|
||||
Map options = new HashMap();
|
||||
options.put(Library.OPTION_TYPE_MAPPER, mapper);
|
||||
DirectMapping lib = new DirectMapping(options);
|
||||
assertEquals("Wrong type mapper for direct mapping",
|
||||
mapper, Native.getTypeMapper(DirectMapping.class));
|
||||
assertEquals("Wrong type mapper for direct mapping nested structure",
|
||||
mapper, Native.getTypeMapper(DirectMapping.DirectStructure.class));
|
||||
assertEquals("Wrong type mapper for direct mapping nested callback",
|
||||
mapper, Native.getTypeMapper(DirectMapping.DirectCallback.class));
|
||||
}
|
||||
|
||||
private static class TestCallback implements Callback {
|
||||
public static final TypeMapper TYPE_MAPPER = new DefaultTypeMapper();
|
||||
public void callback() { }
|
||||
}
|
||||
public void testGetTypeMapperFromCallbackInterface() throws Exception {
|
||||
assertEquals("Wrong type mapper for callback class",
|
||||
TestCallback.TYPE_MAPPER,
|
||||
Native.getTypeMapper(TestCallback.class));
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
junit.textui.TestRunner.run(NativeTest.class);
|
||||
|
||||
@@ -227,6 +227,33 @@ public class PointerTest extends TestCase {
|
||||
p, Native.getDirectBufferPointer(b.asFloatBuffer()));
|
||||
assertEquals("DoubleBuffer Pointer does not match",
|
||||
p, Native.getDirectBufferPointer(b.asDoubleBuffer()));
|
||||
|
||||
assertEquals("Wrong direct buffer address",
|
||||
p, Native.getDirectBufferPointer(b));
|
||||
}
|
||||
|
||||
public static class TestPointerType extends PointerType {
|
||||
public TestPointerType() { }
|
||||
public TestPointerType(Pointer p) { super(p); }
|
||||
}
|
||||
|
||||
public void testSetNativeMapped() {
|
||||
Pointer p = new Memory(Pointer.SIZE);
|
||||
TestPointerType tp = new TestPointerType(p);
|
||||
|
||||
p.setValue(0, tp, tp.getClass());
|
||||
|
||||
assertEquals("Wrong value written", p, p.getPointer(0));
|
||||
}
|
||||
|
||||
public void testGetNativeMapped() {
|
||||
Pointer p = new Memory(Pointer.SIZE);
|
||||
p.setPointer(0, null);
|
||||
Object o = p.getValue(0, TestPointerType.class, null);
|
||||
assertNull("Wrong empty value: " + o, o);
|
||||
p.setPointer(0, p);
|
||||
TestPointerType tp = new TestPointerType(p);
|
||||
assertEquals("Wrong value", tp, p.getValue(0, TestPointerType.class, null));
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
@@ -1,194 +0,0 @@
|
||||
/* Copyright (c) 2009 Timothy Wall, All Rights Reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
* <p/>
|
||||
* This library 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 for more details.
|
||||
*/
|
||||
package com.sun.jna;
|
||||
|
||||
import junit.framework.*;
|
||||
import com.sun.jna.*;
|
||||
import java.lang.ref.*;
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
public class RawTest extends TestCase {
|
||||
|
||||
private static final String BUILDDIR =
|
||||
System.getProperty("jna.builddir",
|
||||
"build" + (Platform.is64Bit() ? "-d64" : ""));
|
||||
|
||||
private static class JNI {
|
||||
static {
|
||||
String path = BUILDDIR + "/native/" + System.mapLibraryName("testlib");;
|
||||
if (!new File(path).isAbsolute()) {
|
||||
path = System.getProperty("user.dir") + "/" + path;
|
||||
}
|
||||
if (path.endsWith(".jnilib")) {
|
||||
path = path.replace(".jnilib", ".dylib");
|
||||
}
|
||||
System.load(path);
|
||||
}
|
||||
|
||||
private static native double cos(double x);
|
||||
}
|
||||
|
||||
public static void main(java.lang.String[] argList) {
|
||||
junit.textui.TestRunner.run(RawTest.class);
|
||||
checkPerformance();
|
||||
}
|
||||
|
||||
static class MathLibrary {
|
||||
|
||||
public static native double cos(double x);
|
||||
|
||||
static {
|
||||
Native.register(Platform.isWindows()?"msvcrt":"m");
|
||||
}
|
||||
}
|
||||
|
||||
interface MathInterface extends Library {
|
||||
double cos(double x);
|
||||
}
|
||||
|
||||
static class CLibrary {
|
||||
public static native Pointer memset(Pointer p, int v, int len);
|
||||
|
||||
static {
|
||||
Native.register(Platform.isWindows()?"msvcrt":"c");
|
||||
}
|
||||
}
|
||||
|
||||
static interface CInterface extends Library {
|
||||
Pointer memset(Pointer p, int v, int len);
|
||||
}
|
||||
|
||||
private static class TestLoader extends URLClassLoader {
|
||||
public TestLoader() throws MalformedURLException {
|
||||
super(new URL[] {
|
||||
new File(BUILDDIR + "/classes").toURI().toURL(),
|
||||
new File(BUILDDIR + "/test-classes").toURI().toURL(),
|
||||
}, null);
|
||||
}
|
||||
}
|
||||
|
||||
public void testRegisterMethods() throws Exception {
|
||||
// Use a dedicated class loader to ensure the class can be gc'd
|
||||
String name = "com.sun.jna.RawTest$MathLibrary";
|
||||
ClassLoader loader = new TestLoader();
|
||||
Class cls = Class.forName(name, true, loader);
|
||||
assertNotNull("Failed loading class", cls);
|
||||
WeakReference ref = new WeakReference(cls);
|
||||
loader = null;
|
||||
cls = null;
|
||||
System.gc();
|
||||
|
||||
for (int i=0;i < 100 && ref.get() != null;i++) {
|
||||
try {
|
||||
Thread.sleep(10); // Give the GC a chance to run
|
||||
System.gc();
|
||||
} finally {}
|
||||
}
|
||||
// TODO: need a real check for freed native memory
|
||||
assertNull("Registered methods not GC'd: " + ref.get(), ref.get());
|
||||
}
|
||||
|
||||
public void testInvokeMethod() {
|
||||
assertEquals("Wrong value", Math.cos(0), MathLibrary.cos(0d));
|
||||
}
|
||||
|
||||
public void testInvokeMethodWithPointer() {
|
||||
assertNull("Returned pointer should be null",
|
||||
CLibrary.memset(null, 0, 0));
|
||||
}
|
||||
|
||||
// Requires java.library.path include testlib
|
||||
public static void checkPerformance() {
|
||||
System.out.println("Checking performance of different access methods");
|
||||
|
||||
String mname = Platform.isWindows()?"msvcrt":"m";
|
||||
MathInterface mlib = (MathInterface)
|
||||
Native.loadLibrary(mname, MathInterface.class);
|
||||
Function f = NativeLibrary.getInstance(mname).getFunction("cos");
|
||||
final int COUNT = 1000000;
|
||||
Object[] args = { new Double(0) };
|
||||
long start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
mlib.cos(0d);
|
||||
}
|
||||
long delta = System.currentTimeMillis() - start;
|
||||
System.out.println("cos (JNA interface): " + delta + "ms");
|
||||
|
||||
start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
f.invokeDouble(args);
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
System.out.println("cos (JNA Function): " + delta + "ms");
|
||||
|
||||
start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
MathLibrary.cos(0d);
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
System.out.println("cos (JNA raw): " + delta + "ms");
|
||||
|
||||
start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
JNI.cos(0d);
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
System.out.println("cos (JNI): " + delta + "ms");
|
||||
|
||||
start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
Math.cos(0d);
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
System.out.println("cos (pure java): " + delta + "ms");
|
||||
|
||||
// memset
|
||||
String cname = Platform.isWindows()?"msvcrt":"c";
|
||||
CInterface clib = (CInterface)
|
||||
Native.loadLibrary(cname, CInterface.class);
|
||||
start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
clib.memset(null, 0, 0);
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
System.out.println("memset (JNA interface): " + delta + "ms");
|
||||
|
||||
f = NativeLibrary.getInstance(cname).getFunction("memset");
|
||||
args = new Object[] { null, new Integer(0), new Integer(0)};
|
||||
start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
f.invokePointer(args);
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
System.out.println("memset (JNA Function): " + delta + "ms");
|
||||
|
||||
f = NativeLibrary.getInstance(cname).getFunction("memset");
|
||||
start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
CLibrary.memset(null, 0, 0);
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
System.out.println("memset (JNA raw): " + delta + "ms");
|
||||
|
||||
start = System.currentTimeMillis();
|
||||
for (int i=0;i < COUNT;i++) {
|
||||
Pointer._setMemory(0L, 0L, (byte)0);
|
||||
}
|
||||
delta = System.currentTimeMillis() - start;
|
||||
System.out.println("memset (JNI): " + delta + "ms");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
package com.sun.jna;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
@@ -97,9 +98,10 @@ public class ReturnTypesTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testReturnObject() throws Exception {
|
||||
lib = (TestLibrary)Native.loadLibrary("testlib", TestLibrary.class, new HashMap() { {
|
||||
Map options = new HashMap() { {
|
||||
put(Library.OPTION_ALLOW_OBJECTS, Boolean.TRUE);
|
||||
}});
|
||||
}};
|
||||
lib = (TestLibrary)Native.loadLibrary("testlib", TestLibrary.class, options);
|
||||
assertNull("null value not returned", lib.returnObjectArgument(null));
|
||||
final Object VALUE = new Object() {
|
||||
public String toString() {
|
||||
@@ -110,7 +112,6 @@ public class ReturnTypesTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testReturnObjectUnsupported() throws Exception {
|
||||
lib = (TestLibrary)Native.loadLibrary("testlib", TestLibrary.class);
|
||||
try {
|
||||
lib.returnObjectArgument(new TestLibrary.TestObject());
|
||||
fail("Java Object return is not supported, should throw IllegalArgumentException");
|
||||
@@ -181,9 +182,13 @@ public class ReturnTypesTest extends TestCase {
|
||||
return o instanceof Custom && ((Custom)o).value == value;
|
||||
}
|
||||
}
|
||||
public void testInvokeNativeMapped() {
|
||||
NativeMappedLibrary lib = (NativeMappedLibrary)
|
||||
protected NativeMappedLibrary loadNativeMappedLibrary() {
|
||||
return (NativeMappedLibrary)
|
||||
Native.loadLibrary("testlib", NativeMappedLibrary.class);
|
||||
}
|
||||
|
||||
public void testInvokeNativeMapped() {
|
||||
NativeMappedLibrary lib = loadNativeMappedLibrary();
|
||||
final int MAGIC = 0x12345678;
|
||||
final Custom EXPECTED = new Custom(MAGIC);
|
||||
assertEquals("Argument not mapped", EXPECTED, lib.returnInt32Argument(MAGIC));
|
||||
@@ -203,12 +208,13 @@ public class ReturnTypesTest extends TestCase {
|
||||
|
||||
static final String MAGIC = "magic";
|
||||
public void testInvokeString() {
|
||||
assertEquals("Expect string magic", MAGIC, lib.returnStringMagic());
|
||||
assertEquals("Expect String magic", MAGIC, lib.returnStringMagic());
|
||||
}
|
||||
|
||||
public void testInvokeWString() {
|
||||
WString s = lib.returnWStringMagic();
|
||||
assertEquals("Expect wstring magic", new WString(MAGIC), s);
|
||||
assertEquals("Wrong length", MAGIC.length(), s.toString().length());
|
||||
assertEquals("Expect WString magic", new WString(MAGIC), s);
|
||||
}
|
||||
|
||||
public void testInvokeStructure() {
|
||||
|
||||
Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais
Referência em uma Nova Issue
Bloquear um usuário