diff --git a/build.xml b/build.xml index f29dc5f..ee45946 100644 --- a/build.xml +++ b/build.xml @@ -72,7 +72,7 @@ - + diff --git a/native/Makefile b/native/Makefile index 1f0ea70..02d4c7d 100644 --- a/native/Makefile +++ b/native/Makefile @@ -48,7 +48,7 @@ OS=$(shell uname | sed -e 's/CYGWIN.*/win32/g' \ -e 's/Linux.*/linux/g') JNA_JNI_VERSION=4.0.0 # auto-generated by ant -CHECKSUM=1a6047467b59e8748f975e03016ce3d9 # auto-generated by ant +CHECKSUM=3f99b7ecf15cd6a6fc62cc9420598381 # auto-generated by ant JAVA_INCLUDES=-I"$(JAVA_HOME)/include" \ -I"$(JAVA_HOME)/include/$(OS)" @@ -63,7 +63,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="$(COPT) $(CDEBUG)" CPPFLAGS="$(CDEFINES)" +FFI_ENV=CC="$(CC)" CFLAGS="$(COPT) $(CDEBUG) -std=gnu99" CPPFLAGS="$(CDEFINES)" FFI_CONFIG=--enable-static --disable-shared --with-pic=yes endif LIBRARY=$(BUILD)/$(LIBPFX)jnidispatch$(JNISFX) @@ -91,7 +91,7 @@ CFLAGS_EXTRA= COUT=-o $@ CINCLUDES=$(JAVA_INCLUDES) -I"$(JAVAH)" -I$(FFI_BUILD)/include CDEFINES=-D_REENTRANT -PCFLAGS=-W -Wall -Wno-unused -Wno-parentheses +PCFLAGS=-W -std=gnu99 -Wall -Wno-unused -Wno-parentheses CFLAGS=$(PCFLAGS) $(CFLAGS_EXTRA) $(COPT) $(CDEBUG) $(CDEFINES) $(CINCLUDES) \ -DJNA_JNI_VERSION='"$(JNA_JNI_VERSION)"' -DCHECKSUM='"$(CHECKSUM)"' LDFLAGS=-o $@ -shared @@ -132,7 +132,7 @@ JAVA_INCLUDES= CINCLUDES+=-I"$(NDK_PLATFORM)/arch-$(ARCH)/usr/include" # -I/usr/include LIBS=-nostdlib -L"$(NDK_PLATFORM)/arch-$(ARCH)/usr/lib/" -lgcc -lc -ldl -lm LDFLAGS+=-Wl,-shared,-Bsymbolic -FFI_ENV=CPP="$(CPP)" CC="$(CC)" CFLAGS="$(COPT) $(CDEBUG) $(CINCLUDES)" CPPFLAGS="$(CDEFINES) $(CINCLUDES)" LIBS="$(LIBS)" RANLIB="$(RANLIB)" +FFI_ENV=CPP="$(CPP)" CC="$(CC)" CFLAGS="$(COPT) $(CDEBUG) $(CINCLUDES) -std=gnu99" CPPFLAGS="$(CDEFINES) $(CINCLUDES)" LIBS="$(LIBS)" RANLIB="$(RANLIB)" FFI_CONFIG=--enable-static --disable-shared --with-pic=yes --host=$(HOST) endif @@ -273,7 +273,7 @@ endif ifeq ($(OS),aix) LIBSFX=.a PCFLAGS+=-fPIC -CDEFINES+=-DHAVE_PROTECTION -DNO_JAWT -Wall -D_AIX -DPOWERPC_AIX -D_THREAD_SAFE_ERRNO +CDEFINES+=-DHAVE_PROTECTION -DNO_JAWT -std=gnu99 -Wall -D_AIX -DPOWERPC_AIX -D_THREAD_SAFE_ERRNO COPT+=-D_AIX -DPOWERPC_AIX -mxl-compat LDFLAGS+=-Wl,-lc128,-lc,-lm,-lpthread FFI_ENV+=AR_FLAGS="-X32_64 cru" @@ -322,7 +322,7 @@ JAVA_INCLUDES=-I/System/Library/Frameworks/JavaVM.framework/Headers DEFAULT_ARCH=$(shell arch) ARCH=$(shell arch) HOST_CONFIG=--host $(ARCH)-apple-darwin -FFI_ENV += CC="$(CC)" CFLAGS="-arch $(ARCH) $(ISYSROOT) $(COPT) $(CDEBUG)" CPPFLAGS="$(CDEFINES)" LD="$(LD) -arch $(ARCH)" +FFI_ENV += CC="$(CC)" CFLAGS="-arch $(ARCH) $(ISYSROOT) $(COPT) $(CDEBUG) -std=gnu99" CPPFLAGS="$(CDEFINES)" LD="$(LD) -arch $(ARCH)" ALT_ARCHS= ifneq ($(ARCH),i386) ALT_ARCHS+=i386 @@ -431,7 +431,7 @@ ifneq ($(SDKROOT),) if [ ! -f $(BUILD)/libffi.$$arch/Makefile ]; then \ echo "Configuring libffi ($$arch)"; \ (cd $(BUILD)/libffi.$$arch \ - && CC="$(CC)" CFLAGS="-arch $$arch $(ISYSROOT) $(COPT) $(CDEBUG)" CPPFLAGS="$(CDEFINES)" \ + && CC="$(CC)" CFLAGS="-arch $$arch $(ISYSROOT) $(COPT) $(CDEBUG) -std=gnu99" CPPFLAGS="$(CDEFINES)" \ LDFLAGS="-arch $$arch" \ $(FFI_SRC)/configure $(FFI_CONFIG) --host=$$arch-apple-darwin --disable-dependency-tracking); \ fi; \ diff --git a/native/callback.c b/native/callback.c index a4ccf5e..b311f3f 100644 --- a/native/callback.c +++ b/native/callback.c @@ -379,7 +379,7 @@ callback_invoke(JNIEnv* env, callback *cb, ffi_cif* cif, void *resp, void **cbar *((void **)args[i+3]) = fromNative(env, cb->arg_classes[i], cif->arg_types[i], cbargs[i], JNI_FALSE); break; case CVT_POINTER: - *((void **)args[i+3]) = newJavaPointer(env, *(void **)cbargs[i]); + *((void **)args[i+3]) = newJavaPointer(env, *(void **)cbargs[i], cif); break; case CVT_STRING: *((void **)args[i+3]) = newJavaString(env, *(void **)cbargs[i], cb->encoding); @@ -476,7 +476,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->arg_jtypes[i], cbargs[i], JNI_FALSE); + jobject arg = new_object(env, cb->arg_jtypes[i], cbargs[i], JNI_FALSE, cif); (*env)->SetObjectArrayElement(env, array, i, arg); } result = (*env)->CallObjectMethod(env, self, cb->methodID, array); diff --git a/native/dispatch.c b/native/dispatch.c index 71fd083..e6fa505 100644 --- a/native/dispatch.c +++ b/native/dispatch.c @@ -208,6 +208,7 @@ static jfieldID FID_Float_value; static jfieldID FID_Double_value; static jfieldID FID_Pointer_peer; +static jfieldID FID_Pointer_cif; static jfieldID FID_Structure_memory; static jfieldID FID_Structure_typeInfo; static jfieldID FID_IntegerType_value; @@ -875,11 +876,11 @@ newJavaString(JNIEnv *env, const char *ptr, const char* charset) } jobject -newJavaPointer(JNIEnv *env, void *p) +newJavaPointer(JNIEnv *env, void *p, ffi_cif *cif) { jobject obj = NULL; if (p != NULL) { - obj = (*env)->NewObject(env, classPointer, MID_Pointer_init, A2L(p)); + obj = (*env)->NewObject(env, classPointer, MID_Pointer_init, A2L(p), cif == NULL ? 0 : A2L(cif)); } return obj; } @@ -901,7 +902,7 @@ jobject newJavaCallback(JNIEnv* env, void* fptr, jclass type) { if (fptr != NULL) { - jobject ptr = newJavaPointer(env, fptr); + jobject ptr = newJavaPointer(env, fptr, NULL); return (*env)->CallStaticObjectMethod(env, classCallbackReference, MID_CallbackReference_getCallback, type, ptr, JNI_TRUE); @@ -1139,7 +1140,7 @@ toNativeTypeMapped(JNIEnv* env, jobject obj, void* valuep, size_t size, jobject static void fromNativeTypeMapped(JNIEnv* env, jobject from_native, void* resp, ffi_type* type, jclass javaClass, void* result) { int jtype = get_jtype_from_ffi_type(type); - jobject value = new_object(env, (char)jtype, resp, JNI_TRUE); + jobject value = new_object(env, (char)jtype, resp, JNI_TRUE, NULL); if (!(*env)->ExceptionCheck(env)) { jobject obj = (*env)->CallStaticObjectMethod(env, classNative, MID_Native_fromNativeTypeMapped, @@ -1156,7 +1157,7 @@ fromNativeTypeMapped(JNIEnv* env, jobject from_native, void* resp, ffi_type* typ jobject fromNative(JNIEnv* env, jclass javaClass, ffi_type* type, void* resp, jboolean promote) { int jtype = get_jtype_from_ffi_type(type); - jobject value = new_object(env, (char)jtype, resp, promote); + jobject value = new_object(env, (char)jtype, resp, promote, NULL); if (!(*env)->ExceptionCheck(env)) { return (*env)->CallStaticObjectMethod(env, classNative, MID_Native_fromNative, @@ -1516,12 +1517,12 @@ extract_value(JNIEnv* env, jobject value, void* resp, size_t size, jboolean prom /** Construct a new Java object from a native value. */ jobject -new_object(JNIEnv* env, char jtype, void* valuep, jboolean promote) { +new_object(JNIEnv* env, char jtype, void* valuep, jboolean promote, ffi_cif *cif) { switch(jtype) { case 's': - return newJavaPointer(env, valuep); + return newJavaPointer(env, valuep, cif); case '*': - return newJavaPointer(env, *(void**)valuep); + return newJavaPointer(env, *(void**)valuep, cif); case 'J': return (*env)->NewObject(env, classLong, MID_Long_init, *(jlong *)valuep); @@ -1693,7 +1694,7 @@ method_handler(ffi_cif* cif, void* volatile resp, void** argp, void *cdata) { int jtype = get_jtype_from_ffi_type(data->closure_cif.arg_types[i+2]); jobject obj = jtype == '*' ? *(void **)valuep - : new_object(env, (char)jtype, valuep, JNI_FALSE); + : new_object(env, (char)jtype, valuep, JNI_FALSE, cif); if (cif->arg_types[i+2]->size < data->cif.arg_types[i]->size) { args[i] = alloca(data->cif.arg_types[i]->size); } @@ -1814,7 +1815,7 @@ method_handler(ffi_cif* cif, void* volatile resp, void** argp, void *cdata) { *(void **)oldresp = fromNative(env, data->closure_rclass, data->cif.rtype, resp, JNI_TRUE); break; case CVT_POINTER: - *(void **)resp = newJavaPointer(env, *(void **)resp); + *(void **)resp = newJavaPointer(env, *(void **)resp, cif); break; case CVT_STRING: *(void **)resp = newJavaString(env, *(void **)resp, data->encoding); @@ -2655,7 +2656,7 @@ Java_com_sun_jna_Native_initIDs(JNIEnv *env, jclass cls) { "Can't obtain class com.sun.jna.Pointer"); } else if (!LOAD_MID(env, MID_Pointer_init, classPointer, - "", "(J)V")) { + "", "(JJ)V")) { throwByName(env, EUnsatisfiedLink, "Can't obtain constructor for class com.sun.jna.Pointer"); } @@ -2663,6 +2664,10 @@ Java_com_sun_jna_Native_initIDs(JNIEnv *env, jclass cls) { throwByName(env, EUnsatisfiedLink, "Can't obtain peer field ID for class com.sun.jna.Pointer"); } + else if (!LOAD_FID(env, FID_Pointer_cif, classPointer, "cif", "J")) { + throwByName(env, EUnsatisfiedLink, + "Can't obtain libffi cif field ID for class com.sun.jna.Pointer"); + } else if (!(classNative = (*env)->NewWeakGlobalRef(env, cls))) { throwByName(env, EUnsatisfiedLink, "Can't obtain global reference for class com.sun.jna.Native"); @@ -2839,7 +2844,7 @@ Java_com_sun_jna_Native_initIDs(JNIEnv *env, jclass cls) { throwByName(env, EUnsatisfiedLink, field); return; } - (*env)->SetStaticObjectField(env, cls, fid, newJavaPointer(env, types[i])); + (*env)->SetStaticObjectField(env, cls, fid, newJavaPointer(env, types[i], NULL)); } } } @@ -3352,6 +3357,87 @@ Java_com_sun_jna_Native_setDetachState(JNIEnv* env, jclass UNUSED(cls), jboolean JNA_detach(env, d, L2A(flag)); } +/* libffi variadic closure functions */ + +JNIEXPORT jbyte JNICALL +Java_com_sun_jna_Native_ffi_1closure_1va_1sint8(JNIEnv *env, jclass UNUSED(cls), jlong cif) +{ + return ffi_closure_va_sint8(L2A(cif)); +} + +JNIEXPORT jshort JNICALL +Java_com_sun_jna_Native_ffi_1closure_1va_1sint16(JNIEnv *env, jclass UNUSED(cls), jlong cif) +{ + return ffi_closure_va_sint16(L2A(cif)); +} + +JNIEXPORT jint JNICALL +Java_com_sun_jna_Native_ffi_1closure_1va_1sint32(JNIEnv *env, jclass UNUSED(cls), jlong cif) +{ + return ffi_closure_va_sint32(L2A(cif)); +} + +JNIEXPORT jlong JNICALL +Java_com_sun_jna_Native_ffi_1closure_1va_1sint64(JNIEnv *env, jclass UNUSED(cls), jlong cif) +{ + return ffi_closure_va_sint64(L2A(cif)); +} + +JNIEXPORT jbyte JNICALL +Java_com_sun_jna_Native_ffi_1closure_1va_1uint8(JNIEnv *env, jclass UNUSED(cls), jlong cif) +{ + return ffi_closure_va_uint8(L2A(cif)); +} + +JNIEXPORT jchar JNICALL +Java_com_sun_jna_Native_ffi_1closure_1va_1uint16(JNIEnv *env, jclass UNUSED(cls), jlong cif) +{ + return ffi_closure_va_uint16(L2A(cif)); +} + +JNIEXPORT jint JNICALL +Java_com_sun_jna_Native_ffi_1closure_1va_1uint32(JNIEnv *env, jclass UNUSED(cls), jlong cif) +{ + return ffi_closure_va_uint32(L2A(cif)); +} + +JNIEXPORT jlong JNICALL +Java_com_sun_jna_Native_ffi_1closure_1va_1uint64(JNIEnv *env, jclass UNUSED(cls), jlong cif) +{ + return ffi_closure_va_uint64(L2A(cif)); +} + +JNIEXPORT jfloat JNICALL +Java_com_sun_jna_Native_ffi_1closure_1va_1float(JNIEnv *env, jclass UNUSED(cls), jlong cif) +{ + return ffi_closure_va_float(L2A(cif)); +} + +JNIEXPORT jdouble JNICALL +Java_com_sun_jna_Native_ffi_1closure_1va_1double(JNIEnv *env, jclass UNUSED(cls), jlong cif) +{ + return ffi_closure_va_double(L2A(cif)); +} + +JNIEXPORT jlong JNICALL +Java_com_sun_jna_Native__1ffi_1closure_1va_1slong(JNIEnv *env, jclass UNUSED(cls), jlong cif) +{ + return ffi_closure_va_slong(L2A(cif)); +} + +JNIEXPORT jlong JNICALL +Java_com_sun_jna_Native__1ffi_1closure_1va_1ulong(JNIEnv *env, jclass UNUSED(cls), jlong cif) +{ + return ffi_closure_va_ulong(L2A(cif)); +} + +JNIEXPORT jlong JNICALL +Java_com_sun_jna_Native__1ffi_1closure_1va_1pointer(JNIEnv *env, jclass UNUSED(cls), jlong cif) +{ + void *result = ffi_closure_va_pointer(L2A(cif)); + return A2L(result); +} + #ifdef __cplusplus } #endif diff --git a/native/dispatch.h b/native/dispatch.h index 602b304..71da754 100644 --- a/native/dispatch.h +++ b/native/dispatch.h @@ -186,13 +186,13 @@ extern callback* create_callback(JNIEnv*, jobject, jobject, callconv_t, jint, jstring); extern void free_callback(JNIEnv*, callback*); extern void extract_value(JNIEnv*, jobject, void*, size_t, jboolean); -extern jobject new_object(JNIEnv*, char, void*, jboolean); +extern jobject new_object(JNIEnv*, char, void*, jboolean, ffi_cif *cif); extern jboolean is_protected(); extern int get_conversion_flag(JNIEnv*, jclass); extern jboolean ffi_error(JNIEnv*,const char*,ffi_status); extern const char* newCStringUTF8(JNIEnv*, jstring); -extern jobject newJavaPointer(JNIEnv*, void*); +extern jobject newJavaPointer(JNIEnv*, void*, ffi_cif*); extern jstring newJavaString(JNIEnv*, const char*, const char*); extern jobject newJavaWString(JNIEnv*, const wchar_t*); extern jobject newJavaStructure(JNIEnv*, void*, jclass); diff --git a/native/libffi/Makefile.am b/native/libffi/Makefile.am index bf0156f..4218cd1 100644 --- a/native/libffi/Makefile.am +++ b/native/libffi/Makefile.am @@ -102,7 +102,8 @@ toolexeclib_LTLIBRARIES = libffi.la noinst_LTLIBRARIES = libffi_convenience.la libffi_la_SOURCES = src/prep_cif.c src/types.c \ - src/raw_api.c src/java_raw_api.c src/closures.c + src/raw_api.c src/java_raw_api.c src/closures.c \ + src/closures_va.c pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libffi.pc diff --git a/native/libffi/Makefile.in b/native/libffi/Makefile.in index 4b6abe5..7b50c7a 100644 --- a/native/libffi/Makefile.in +++ b/native/libffi/Makefile.in @@ -149,7 +149,7 @@ LTLIBRARIES = $(noinst_LTLIBRARIES) $(toolexeclib_LTLIBRARIES) libffi_la_LIBADD = am__dirstamp = $(am__leading_dot)dirstamp am_libffi_la_OBJECTS = src/prep_cif.lo src/types.lo src/raw_api.lo \ - src/java_raw_api.lo src/closures.lo + src/java_raw_api.lo src/closures.lo src/closures_va.lo @FFI_DEBUG_TRUE@am__objects_1 = src/debug.lo @MIPS_TRUE@am__objects_2 = src/mips/ffi.lo src/mips/o32.lo \ @MIPS_TRUE@ src/mips/n32.lo @@ -217,7 +217,7 @@ libffi_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(libffi_la_LDFLAGS) $(LDFLAGS) -o $@ libffi_convenience_la_LIBADD = am__objects_35 = src/prep_cif.lo src/types.lo src/raw_api.lo \ - src/java_raw_api.lo src/closures.lo + src/java_raw_api.lo src/closures.lo src/closures_va.lo am_libffi_convenience_la_OBJECTS = $(am__objects_35) am__objects_36 = $(am__objects_1) $(am__objects_2) $(am__objects_3) \ $(am__objects_4) $(am__objects_5) $(am__objects_6) \ @@ -556,7 +556,8 @@ MAKEOVERRIDES = toolexeclib_LTLIBRARIES = libffi.la noinst_LTLIBRARIES = libffi_convenience.la libffi_la_SOURCES = src/prep_cif.c src/types.c \ - src/raw_api.c src/java_raw_api.c src/closures.c + src/raw_api.c src/java_raw_api.c src/closures.c \ + src/closures_va.c pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libffi.pc @@ -690,6 +691,7 @@ src/types.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) src/raw_api.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) src/java_raw_api.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) src/closures.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) +src/closures_va.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) src/debug.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) src/mips/$(am__dirstamp): @$(MKDIR_P) src/mips @@ -1017,6 +1019,7 @@ distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/closures.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/closures_va.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/debug.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/java_raw_api.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/prep_cif.Plo@am__quote@ diff --git a/native/libffi/include/ffi.h.in b/native/libffi/include/ffi.h.in index a51583b..78d4d5e 100644 --- a/native/libffi/include/ffi.h.in +++ b/native/libffi/include/ffi.h.in @@ -75,6 +75,11 @@ extern "C" { #include #include +/* C99 int data types */ +#if __STDC_VERSION__ >= 199901L +# include +#endif + /* LONG_LONG_MAX is not always defined (not if STRICT_ANSI, for example). But we can find it either under the correct ANSI name, or under GNU C's internal name. */ @@ -219,8 +224,18 @@ typedef struct { #ifdef FFI_EXTRA_CIF_FIELDS FFI_EXTRA_CIF_FIELDS; #endif +#ifdef FFI_CLOSURE_VA_LIST + ffi_closure_va_list va; +#endif } ffi_cif; +/* Used internally and used to access variadic arguments in closures */ +#ifdef FFI_CLOSURE_VA_LIST +ffi_status ffi_closure_va_arg(ffi_cif *cif, + ffi_type *type, + void **va_value); +#endif + /* Used internally, but overridden by some architectures */ ffi_status ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi, @@ -436,6 +451,42 @@ void ffi_call(ffi_cif *cif, /* Useful for eliminating compiler warnings */ #define FFI_FN(f) ((void (*)(void))f) +/* ---- Definitions for variadic closures -------------------------------- */ + +#ifdef FFI_CLOSURE_VA_LIST + +# if __STDC_VERSION__ >= 199901L +/* C99 data types */ +int8_t ffi_closure_va_sint8 (ffi_cif *cif); +int16_t ffi_closure_va_sint16 (ffi_cif *cif); +int32_t ffi_closure_va_sint32 (ffi_cif *cif); +int64_t ffi_closure_va_sint64 (ffi_cif *cif); +uint8_t ffi_closure_va_uint8 (ffi_cif *cif); +uint16_t ffi_closure_va_uint16 (ffi_cif *cif); +uint32_t ffi_closure_va_uint32 (ffi_cif *cif); +uint64_t ffi_closure_va_uint64 (ffi_cif *cif); +# endif /* __STDC_VERSION__ >= 199901L */ + +# ifndef LIBFFI_HIDE_BASIC_TYPES +signed char ffi_closure_va_schar (ffi_cif *cif); +short ffi_closure_va_sshort (ffi_cif *cif); +int ffi_closure_va_sint (ffi_cif *cif); +long ffi_closure_va_slong (ffi_cif *cif); +unsigned char ffi_closure_va_uchar (ffi_cif *cif); +unsigned short ffi_closure_va_ushort (ffi_cif *cif); +unsigned int ffi_closure_va_uint (ffi_cif *cif); +unsigned long ffi_closure_va_ulong (ffi_cif *cif); +# endif /* ! LIBFFI_HIDE_BASIC_TYPES */ + +float ffi_closure_va_float (ffi_cif *cif); +double ffi_closure_va_double (ffi_cif *cif); +void *ffi_closure_va_pointer (ffi_cif *cif); + +# if @HAVE_LONG_DOUBLE@ +long double ffi_closure_va_longdouble (ffi_cif *cif); +# endif /* HAVE_LONG_DOUBLE */ +#endif /* FFI_CLOSURE_VA_LIST */ + /* ---- Definitions shared with assembly code ---------------------------- */ #endif diff --git a/native/libffi/include/ffi_common.h b/native/libffi/include/ffi_common.h index 650ca69..e0dbc8e 100644 --- a/native/libffi/include/ffi_common.h +++ b/native/libffi/include/ffi_common.h @@ -64,10 +64,12 @@ void ffi_type_test(ffi_type *a, char *file, int line); #define FFI_ASSERT(x) ((x) ? (void)0 : ffi_assert(#x, __FILE__,__LINE__)) #define FFI_ASSERT_AT(x, f, l) ((x) ? 0 : ffi_assert(#x, (f), (l))) #define FFI_ASSERT_VALID_TYPE(x) ffi_type_test (x, __FILE__, __LINE__) +#define FFI_RUN_OK(x) ((x) == FFI_OK ? (void)0 : ffi_assert(#x, __FILE__,__LINE__)) #else #define FFI_ASSERT(x) #define FFI_ASSERT_AT(x, f, l) #define FFI_ASSERT_VALID_TYPE(x) +#define FFI_RUN_OK(x) ((x)) #endif #define ALIGN(v, a) (((((size_t) (v))-1) | ((a)-1))+1) diff --git a/native/libffi/src/closures_va.c b/native/libffi/src/closures_va.c new file mode 100644 index 0000000..9d5a955 --- /dev/null +++ b/native/libffi/src/closures_va.c @@ -0,0 +1,168 @@ +/* ----------------------------------------------------------------------- + closures_va.c + + Code to access variadic arguments inside of closures. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + 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. + ----------------------------------------------------------------------- */ + +#include +#include + +#if FFI_CLOSURES +# if __STDC_VERSION__ >= 199901L + +/* Note: int8_t, uint8_t, int16_t and uint16_t are promoted to int in '...' + */ +int8_t +ffi_closure_va_sint8(ffi_cif *cif) { + return ffi_closure_va_sint32(cif); +} + +uint8_t +ffi_closure_va_uint8(ffi_cif *cif) { + return ffi_closure_va_uint32(cif); +} + +int16_t +ffi_closure_va_sint16(ffi_cif *cif) { + return ffi_closure_va_sint32(cif); +} + +uint16_t +ffi_closure_va_uint16(ffi_cif *cif) { + return ffi_closure_va_uint32(cif); +} + +int32_t +ffi_closure_va_sint32(ffi_cif *cif) { + void *val; + FFI_RUN_OK(ffi_closure_va_arg(cif, &ffi_type_sint32, &val)); + return *(int32_t *)val; +} + +uint32_t +ffi_closure_va_uint32(ffi_cif *cif) { + void *val; + FFI_RUN_OK(ffi_closure_va_arg(cif, &ffi_type_uint32, &val)); + return *(uint32_t *)val; +} + +int64_t +ffi_closure_va_sint64(ffi_cif *cif) { + void *val; + FFI_RUN_OK(ffi_closure_va_arg(cif, &ffi_type_sint64, &val)); + return *(int64_t *)val; +} + +uint64_t +ffi_closure_va_uint64(ffi_cif *cif) { + void *val; + FFI_RUN_OK(ffi_closure_va_arg(cif, &ffi_type_uint64, &val)); + return *(uint64_t *)val; +} +# endif /* __STDC_VERSION__ >= 199901L */ + +# if !defined (LIBFFI_HIDE_BASIC_TYPES) + +/* Note: char, uchar, short and ushort are promoted to int in '...' + */ +signed char +ffi_closure_va_schar(ffi_cif *cif) { + return ffi_closure_va_sint(cif); +} + +unsigned char +ffi_closure_va_uchar(ffi_cif *cif) { + return ffi_closure_va_uint(cif); +} + +short +ffi_closure_va_sshort(ffi_cif *cif) { + return ffi_closure_va_sint(cif); +} + +unsigned short +ffi_closure_va_ushort(ffi_cif *cif) { + return ffi_closure_va_uint(cif); +} + +int +ffi_closure_va_sint(ffi_cif *cif) { + void *val; + FFI_RUN_OK(ffi_closure_va_arg(cif, &ffi_type_sint, &val)); + return *(int *)val; +} + +unsigned int +ffi_closure_va_uint(ffi_cif *cif) { + void *val; + FFI_RUN_OK(ffi_closure_va_arg(cif, &ffi_type_uint, &val)); + return *(unsigned int *)val; +} + +long +ffi_closure_va_slong(ffi_cif *cif) { + void *val; + FFI_RUN_OK(ffi_closure_va_arg(cif, &ffi_type_slong, &val)); + return *(long *)val; +} + +unsigned long +ffi_closure_va_ulong(ffi_cif *cif) { + void *val; + FFI_RUN_OK(ffi_closure_va_arg(cif, &ffi_type_ulong, &val)); + return *(unsigned long *)val; +} + +# endif /* ! LIBFFI_HIDE_BASIC_TYPES */ + +/* Note: float is promoted to double when passed through '...' + */ + +float +ffi_closure_va_float(ffi_cif *cif) { + return ffi_closure_va_double(cif); +} + +double +ffi_closure_va_double(ffi_cif *cif) { + void *val; + FFI_RUN_OK(ffi_closure_va_arg(cif, &ffi_type_double, &val)); + return *(double *)val; +} + +void * +ffi_closure_va_pointer(ffi_cif *cif) { + void **val; + FFI_RUN_OK(ffi_closure_va_arg(cif, &ffi_type_pointer, (void **)&val)); + return *val; +} + +# if HAVE_LONG_DOUBLE +long double +ffi_closure_va_longdouble(ffi_cif *cif) { + void *val; + FFI_RUN_OK(ffi_closure_va_arg(cif, &ffi_type_longdouble, &val)); + return *(long double *)val; +} +# endif /* HAVE_LONG_DOUBLE */ +#endif /* FFI_CLOSURES */ diff --git a/native/libffi/src/x86/darwin64.S b/native/libffi/src/x86/darwin64.S index 2f7394e..26a912e 100644 --- a/native/libffi/src/x86/darwin64.S +++ b/native/libffi/src/x86/darwin64.S @@ -213,7 +213,7 @@ LUW6: movq %rcx, 24(%rsp) movq %r8, 32(%rsp) movq %r9, 40(%rsp) - jc Lsave_sse + jmp Lsave_sse /* Unconditionally load SSE registers for varargs */ Lret_from_save_sse: movq %r10, %rdi diff --git a/native/libffi/src/x86/ffi.c b/native/libffi/src/x86/ffi.c index c44f4f0..e7996cc 100644 --- a/native/libffi/src/x86/ffi.c +++ b/native/libffi/src/x86/ffi.c @@ -502,71 +502,95 @@ ffi_closure_SYSV_inner (ffi_closure *closure, void **respp, void *args) } #endif /* !X86_WIN64 */ +/* This definition is shared by calls for fixed and variadic arguments. + * You should only check the ABI for variadic arguments. + */ +static ffi_status +ffi_closure_va_arg_internal(ffi_cif *cif, ffi_type *va_type, void **va_value, + int checkABI) +{ + size_t z; + + /* The callee cleans up the stack in Microsoft calling conventions + * stdcall, thiscall and fastcall. You cannot use vararg functions + * with these calling conventions. + * Reference: http://msdn.microsoft.com/en-us/library/zxk0tw93.aspx + * and: http://msdn.microsoft.com/en-us/library/984x0h58.aspx + */ + if (checkABI + && (cif->abi == FFI_STDCALL || cif->abi == FFI_THISCALL + || cif->abi == FFI_FASTCALL)) { + return FFI_BAD_ABI; + } + + /* Align if necessary */ + if ((sizeof(void*) - 1) & (size_t) cif->va.stack) { + cif->va.stack = (char *) ALIGN(cif->va.stack, sizeof(void*)); + } + +#ifdef X86_WIN64 + if (va_type->size > sizeof(ffi_arg) + || (va_type->type == FFI_TYPE_STRUCT + && (va_type->size != 1 && va_type->size != 2 + && va_type->size != 4 && va_type->size != 8))) + { + z = sizeof(void *); + *va_value = *(void **) cif->va.stack; + } + else +#endif + { + z = va_type->size; + /* because we're little endian, this is what it turns into. */ + *va_value = (void*) cif->va.stack; + } + +#ifdef X86_WIN64 + cif->va.stack += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1); +#else + cif->va.stack += z; +#endif + + return FFI_OK; +} + +ffi_status +ffi_closure_va_arg(ffi_cif *cif, ffi_type *va_type, void **va_value) +{ + return ffi_closure_va_arg_internal(cif, va_type, va_value, 1); +} + static void ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue, ffi_cif *cif) { register unsigned int i; - register void **p_argv; - register char *argp; - register ffi_type **p_arg; - argp = stack; + cif->va.stack = stack; + /* Setup the return value */ #ifdef X86_WIN64 if (cif->rtype->size > sizeof(ffi_arg) || (cif->flags == FFI_TYPE_STRUCT && (cif->rtype->size != 1 && cif->rtype->size != 2 && cif->rtype->size != 4 && cif->rtype->size != 8))) { - *rvalue = *(void **) argp; - argp += sizeof(void *); + *rvalue = *(void **) cif->va.stack; + cif->va.stack += sizeof(void *); } #else if ( cif->flags == FFI_TYPE_STRUCT || cif->flags == FFI_TYPE_MS_STRUCT ) { - *rvalue = *(void **) argp; - argp += sizeof(void *); + *rvalue = *(void **) cif->va.stack; + cif->va.stack += sizeof(void *); } #endif - p_argv = avalue; - - for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) - { - size_t z; - - /* Align if necessary */ - if ((sizeof(void*) - 1) & (size_t) argp) { - argp = (char *) ALIGN(argp, sizeof(void*)); - } + /* Setup all fixed arguments. */ + for (i = 0; i < cif->nargs; i++) { + ffi_closure_va_arg_internal(cif, cif->arg_types[i], &avalue[i], 0); + } -#ifdef X86_WIN64 - if ((*p_arg)->size > sizeof(ffi_arg) - || ((*p_arg)->type == FFI_TYPE_STRUCT - && ((*p_arg)->size != 1 && (*p_arg)->size != 2 - && (*p_arg)->size != 4 && (*p_arg)->size != 8))) - { - z = sizeof(void *); - *p_argv = *(void **)argp; - } - else -#endif - { - z = (*p_arg)->size; - - /* because we're little endian, this is what it turns into. */ - - *p_argv = (void*) argp; - } - - p_argv++; -#ifdef X86_WIN64 - argp += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1); -#else - argp += z; -#endif - } - + /* In the closure, you can use ffi_closure_va_arg() to access varargs */ return; } diff --git a/native/libffi/src/x86/ffi64.c b/native/libffi/src/x86/ffi64.c index 2014af2..58e5cf7 100644 --- a/native/libffi/src/x86/ffi64.c +++ b/native/libffi/src/x86/ffi64.c @@ -564,31 +564,98 @@ ffi_prep_closure_loc (ffi_closure* closure, return FFI_OK; } +ffi_status +ffi_closure_va_arg(ffi_cif *cif, ffi_type *va_type, void **va_value) +{ + enum x86_64_reg_class classes[MAX_CLASSES]; + int n; + int ngpr = 0; + int nsse = 0; + + n = examine_argument(va_type, classes, 0, &ngpr, &nsse); + if (n == 0 + || cif->va.gprcount + ngpr > MAX_GPR_REGS + || cif->va.ssecount + nsse > MAX_SSE_REGS) + { + long align = va_type->alignment; + + /* Stack arguments are *always* at least 8 byte aligned. */ + if (align < 8) + align = 8; + + /* Pass this argument in memory. */ + cif->va.stack = (void *) ALIGN (cif->va.stack, align); + *va_value = cif->va.stack; + cif->va.stack += va_type->size; + } + /* If the argument is in a single register, or two consecutive + integer registers, then we can use that address directly. */ + else if (n == 1 + || (n == 2 && !(SSE_CLASS_P (classes[0]) + || SSE_CLASS_P (classes[1])))) + { + /* The argument is in a single register. */ + if (SSE_CLASS_P (classes[0])) + { + *va_value = &cif->va.reg_args->sse[cif->va.ssecount]; + cif->va.ssecount += n; + } + else + { + *va_value = &cif->va.reg_args->gpr[cif->va.gprcount]; + cif->va.gprcount += n; + } + } + /* Otherwise, allocate space to make them consecutive. */ + else + { + char *a = alloca (16); + int j; + + *va_value = a; + for (j = 0; j < n; j++, a += 8) + { + if (SSE_CLASS_P (classes[j])) + memcpy (a, &cif->va.reg_args->sse[cif->va.ssecount++], 8); + else + memcpy (a, &cif->va.reg_args->gpr[cif->va.gprcount++], 8); + } + } + + return FFI_OK; +} + int ffi_closure_unix64_inner(ffi_closure *closure, void *rvalue, struct register_args *reg_args, char *argp) { ffi_cif *cif; void **avalue; - ffi_type **arg_types; - long i, avn; - int gprcount, ssecount, ngpr, nsse; + long i; int ret; cif = closure->cif; avalue = alloca(cif->nargs * sizeof(void *)); - gprcount = ssecount = 0; + /* Setup the va */ + cif->va.stack = argp; + cif->va.gprcount = 0; + cif->va.ssecount = 0; + cif->va.reg_args = reg_args; + + /* Setup the return value */ ret = cif->rtype->type; if (ret != FFI_TYPE_VOID) { enum x86_64_reg_class classes[MAX_CLASSES]; + int ngpr = 0; + int nsse = 0; int n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse); if (n == 0) { /* The return value goes in memory. Arrange for the closure return value to go directly back to the original caller. */ - rvalue = (void *) (unsigned long) reg_args->gpr[gprcount++]; + rvalue = (void *) (unsigned long) cif->va.reg_args->gpr[cif->va.gprcount++]; /* We don't have to do anything in asm for the return. */ ret = FFI_TYPE_VOID; } @@ -604,65 +671,11 @@ ffi_closure_unix64_inner(ffi_closure *closure, void *rvalue, } } - avn = cif->nargs; - arg_types = cif->arg_types; + /* Setup all fixed arguments */ + for (i = 0; i < cif->nargs; ++i) { + ffi_closure_va_arg(cif, cif->arg_types[i], &avalue[i]); + } - for (i = 0; i < avn; ++i) - { - enum x86_64_reg_class classes[MAX_CLASSES]; - int n; - - n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse); - if (n == 0 - || gprcount + ngpr > MAX_GPR_REGS - || ssecount + nsse > MAX_SSE_REGS) - { - long align = arg_types[i]->alignment; - - /* Stack arguments are *always* at least 8 byte aligned. */ - if (align < 8) - align = 8; - - /* Pass this argument in memory. */ - argp = (void *) ALIGN (argp, align); - avalue[i] = argp; - argp += arg_types[i]->size; - } - /* If the argument is in a single register, or two consecutive - integer registers, then we can use that address directly. */ - else if (n == 1 - || (n == 2 && !(SSE_CLASS_P (classes[0]) - || SSE_CLASS_P (classes[1])))) - { - /* The argument is in a single register. */ - if (SSE_CLASS_P (classes[0])) - { - avalue[i] = ®_args->sse[ssecount]; - ssecount += n; - } - else - { - avalue[i] = ®_args->gpr[gprcount]; - gprcount += n; - } - } - /* Otherwise, allocate space to make them consecutive. */ - else - { - char *a = alloca (16); - int j; - - avalue[i] = a; - for (j = 0; j < n; j++, a += 8) - { - if (SSE_CLASS_P (classes[j])) - memcpy (a, ®_args->sse[ssecount++], 8); - else - memcpy (a, ®_args->gpr[gprcount++], 8); - } - } - } - /* Invoke the closure. */ closure->fun (cif, rvalue, avalue, closure->user_data); diff --git a/native/libffi/src/x86/ffitarget.h b/native/libffi/src/x86/ffitarget.h index 46f294c..b3c9c3b 100644 --- a/native/libffi/src/x86/ffitarget.h +++ b/native/libffi/src/x86/ffitarget.h @@ -72,6 +72,27 @@ typedef signed long ffi_sarg; #endif #endif +#define FFI_CLOSURE_VA_LIST 1 + +#if FFI_CLOSURE_VA_LIST +# if (defined (_WIN64) || defined (X86_WIN64)) || !defined (__x86_64__) +typedef struct { + const char *stack; +} ffi_closure_va_list; +# else +# if defined (__x86_64__) || defined (X86_64) +typedef struct { + int gprcount; + int ssecount; + const char *stack; + struct register_args *reg_args; +} ffi_closure_va_list; +# else +# error "Shouldn't be here for x86 or AMD64" +# endif +# endif +#endif + typedef enum ffi_abi { FFI_FIRST_ABI = 0, diff --git a/native/libffi/src/x86/unix64.S b/native/libffi/src/x86/unix64.S index dcd6bc7..899480a 100644 --- a/native/libffi/src/x86/unix64.S +++ b/native/libffi/src/x86/unix64.S @@ -219,7 +219,7 @@ ffi_closure_unix64: movq %rcx, 24(%rsp) movq %r8, 32(%rsp) movq %r9, 40(%rsp) - jc .Lsave_sse + jmp .Lsave_sse /* Unconditionally load SSE for varargs */ .Lret_from_save_sse: movq %r10, %rdi diff --git a/src/com/sun/jna/Native.java b/src/com/sun/jna/Native.java index 7163c84..eb54422 100644 --- a/src/com/sun/jna/Native.java +++ b/src/com/sun/jna/Native.java @@ -1603,6 +1603,43 @@ public final class Native implements Version { public static native long ffi_prep_closure(long cif, ffi_callback cb); public static native void ffi_free_closure(long closure); + /** Expose FFI closure variadic calls. Exclude variable size aliases */ + public static native byte ffi_closure_va_sint8(long cif); + public static native short ffi_closure_va_sint16(long cif); + public static native int ffi_closure_va_sint32(long cif); + public static native long ffi_closure_va_sint64(long cif); + public static native byte ffi_closure_va_uint8(long cif); + public static native char ffi_closure_va_uint16(long cif); + public static native int ffi_closure_va_uint32(long cif); + public static native long ffi_closure_va_uint64(long cif); + public static native float ffi_closure_va_float(long cif); + public static native double ffi_closure_va_double(long cif); + + // These are private because we expose the version with objects + private static native long _ffi_closure_va_slong(long cif); + private static native long _ffi_closure_va_ulong(long cif); + private static native long _ffi_closure_va_pointer(long cif); + + public static NativeLong ffi_closure_va_slong(long cif) { + return new NativeLong(_ffi_closure_va_slong(cif)); + } + public static NativeLong ffi_closure_va_ulong(long cif) { + return new NativeLong(_ffi_closure_va_ulong(cif)); + } + public static Pointer ffi_closure_va_pointer(long cif) { + long peer = _ffi_closure_va_pointer(cif); + return peer == 0 ? null : new Pointer(peer, cif); + } + +/* These may not work if the size doesn't match Java's + public static native byte ffi_closure_va_schar(long cif); + public static native short ffi_closure_va_sshort(long cif); + public static native int ffi_closure_va_sint(long cif); + public static native byte ffi_closure_va_uchar(long cif); + public static native short ffi_closure_va_ushort(long cif); + public static native int ffi_closure_va_uint(long cif); +*/ + /** Returns the size (calculated by libffi) of the given type. */ static native int initialize_ffi_type(long type_info); diff --git a/src/com/sun/jna/Pointer.java b/src/com/sun/jna/Pointer.java index 9f554cb..b7b25c5 100644 --- a/src/com/sun/jna/Pointer.java +++ b/src/com/sun/jna/Pointer.java @@ -64,7 +64,12 @@ public class Pointer { */ protected long peer; - /** Derived class must assign peer pointer value. */ + /** Pointer value of the real native ffi_cif pointer. Use long to be 64-bit safe. + * Should be used sparingly for variadic functions. + */ + protected long cif = 0; + + /** Derived class must assign peer and optionally cif pointer value. */ Pointer() { } /** Create from native pointer. Don't use this unless you know what @@ -74,6 +79,14 @@ public class Pointer { this.peer = peer; } + /** Create from native pointer. Don't use this unless you know what + * you're doing. + */ + public Pointer(long peer, long cif) { + this.peer = peer; + this.cif = cif; + } + /** Provide a view of this memory using the given offset to calculate a new base address. */ public Pointer share(long offset) { return share(offset, 0); @@ -84,7 +97,7 @@ public class Pointer { */ public Pointer share(long offset, long sz) { if (offset == 0) return this; - return new Pointer(peer + offset); + return new Pointer(peer + offset, cif); } /** Zero memory for the given number of bytes. */ @@ -104,6 +117,7 @@ public class Pointer { public boolean equals(Object o) { if (o == this) return true; if (o == null) return false; + // XXX not checking cif return o instanceof Pointer && ((Pointer)o).peer == peer; } @@ -1304,6 +1318,11 @@ v * @param wide whether to convert from a wide or standard C string p.peer = value; } + /** Read the native peer value. Use with caution. */ + public static long nativeCif(Pointer p) { + return p == null ? 0 : p.cif; + } + /** Pointer which disallows all read/write access. */ private static class Opaque extends Pointer { private Opaque(long peer) { super(peer); }