From f81e3fc6a02f685be6509571a16173da07806fd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Bl=C3=A4sing?= Date: Mon, 29 Jul 2019 18:25:39 +0200 Subject: [PATCH 1/2] [GITHUB-1118] Implement Test for problems when passing int/double mixed union by value --- native/testlib.c | 18 +++++++ test/com/sun/jna/ArgumentsMarshalTest.java | 52 +++++++++++++------ .../sun/jna/DirectArgumentsMarshalTest.java | 7 +++ 3 files changed, 61 insertions(+), 16 deletions(-) diff --git a/native/testlib.c b/native/testlib.c index 609ed75ed..5ea8b605b 100644 --- a/native/testlib.c +++ b/native/testlib.c @@ -946,6 +946,24 @@ returnStringVarArgs2(const char *fmt, ...) { return cp; } +typedef union _MixedUnion1 { + int intValue; + double doubleValue; +} MixedUnion1; + +EXPORT +int stringifyMixedUnion1( + char* buffer, int bufferLength, + int dummyInt1, double dummyDouble1, + MixedUnion1 union1, MixedUnion1 union2, + int dummyInt2, double dummyDouble2) { + return snprintf( + buffer, bufferLength - 1, + "dummyInt1: %d, dummyDouble1: %.0f, dummyInt2: %d, dummyDouble2: %.0f, union1.intValue: %d, union2.doubleValue: %.0f", + dummyInt1, dummyDouble1, dummyInt2, dummyDouble2, + union1.intValue, union2.doubleValue); +} + #if defined(_WIN32) && !defined(_WIN64) && !defined(_WIN32_WCE) /////////////////////////////////////////////////////////////////////// // stdcall tests diff --git a/test/com/sun/jna/ArgumentsMarshalTest.java b/test/com/sun/jna/ArgumentsMarshalTest.java index 468e07d1c..4b2970e90 100644 --- a/test/com/sun/jna/ArgumentsMarshalTest.java +++ b/test/com/sun/jna/ArgumentsMarshalTest.java @@ -29,6 +29,8 @@ import junit.framework.TestCase; import com.sun.jna.ArgumentsMarshalTest.TestLibrary.CheckFieldAlignment; +import com.sun.jna.ArgumentsMarshalTest.TestLibrary.MixedUnion1; +import com.sun.jna.Structure.FieldOrder; /** Exercise a range of native methods. * @@ -41,6 +43,7 @@ public class ArgumentsMarshalTest extends TestCase { public static interface TestLibrary extends Library { + @FieldOrder({ "int8Field", "int16Field", "int32Field", "int64Field", "floatField", "doubleField" }) class CheckFieldAlignment extends Structure { public static class ByValue extends CheckFieldAlignment implements Structure.ByValue { } @@ -54,10 +57,6 @@ public static class ByReference extends CheckFieldAlignment public float floatField; public double doubleField; - @Override - public List getFieldOrder() { - return Arrays.asList(new String[] { "int8Field", "int16Field", "int32Field", "int64Field", "floatField", "doubleField" }); - } public CheckFieldAlignment() { int8Field = (byte)fieldOffset("int8Field"); int16Field = (short)fieldOffset("int16Field"); @@ -119,22 +118,17 @@ public TestPointerType() { } boolean returnBooleanArgument(Object arg); // Structure + @FieldOrder({ "field" }) class MinTestStructure extends Structure { public int field; - @Override - protected List getFieldOrder() { - return Arrays.asList(new String[] { "field" }); - } } Pointer testStructurePointerArgument(MinTestStructure s); + @FieldOrder({ "length", "buffer" }) class VariableSizedStructure extends Structure { public int length; public byte[] buffer; - @Override - protected List getFieldOrder() { - return Arrays.asList(new String[] { "length", "buffer" }); - } + public VariableSizedStructure(String arg) { length = arg.length() + 1; buffer = new byte[length]; @@ -142,17 +136,29 @@ public VariableSizedStructure(String arg) { } } String returnStringFromVariableSizedStructure(VariableSizedStructure s); + + @FieldOrder({ "cb" }) class CbStruct extends Structure { public static interface TestCallback extends Callback { int callback(int arg1, int arg2); } public TestCallback cb; - @Override - protected List getFieldOrder() { - return Arrays.asList(new String[] { "cb" }); - } } void setCallbackInStruct(CbStruct cbstruct); + + class MixedUnion1 extends Union { + public static class ByValue extends MixedUnion1 + implements Structure.ByValue { } + + public int intValue; + public double doubleValue; + } + + int stringifyMixedUnion1( + byte[] buffer, int bufferLength, + int dummyInt1, double dummyDouble1, + MixedUnion1.ByValue union1, MixedUnion1.ByValue union2, + int dummyInt2, double dummyDouble2); } TestLibrary lib; @@ -688,6 +694,20 @@ public void testDisableAutoSynch() { assertEquals("Auto read should be disabled", EXPECTED, s.field); } + public void testUnionCallstack() { + MixedUnion1.ByValue union1 = new MixedUnion1.ByValue(); + MixedUnion1.ByValue union2 = new MixedUnion1.ByValue(); + union1.setType("intValue"); + union1.intValue = 5; + union2.setType("doubleValue"); + union2.doubleValue = 6; + byte[] buffer = new byte[256]; + lib.stringifyMixedUnion1(buffer, buffer.length, 1, 2, union1, union2, 3, 4); + String resultString = Native.toString(buffer); + String expected = "dummyInt1: 1, dummyDouble1: 2, dummyInt2: 3, dummyDouble2: 4, union1.intValue: 5, union2.doubleValue: 6"; + assertEquals(expected, resultString); + } + public static void main(java.lang.String[] argList) { junit.textui.TestRunner.run(ArgumentsMarshalTest.class); } diff --git a/test/com/sun/jna/DirectArgumentsMarshalTest.java b/test/com/sun/jna/DirectArgumentsMarshalTest.java index 2399847c9..b426340d6 100644 --- a/test/com/sun/jna/DirectArgumentsMarshalTest.java +++ b/test/com/sun/jna/DirectArgumentsMarshalTest.java @@ -123,6 +123,13 @@ public void modifyStructureByReferenceArray(CheckFieldAlignment.ByReference[] p, @Override public native void setCallbackInStruct(CbStruct s); + @Override + public native int stringifyMixedUnion1( + byte[] buffer, int bufferLength, + int dummyInt1, double dummyDouble1, + MixedUnion1.ByValue union1, MixedUnion1.ByValue union2, + int dummyInt2, double dummyDouble2); + static { Native.register("testlib"); } From 678d82ad88d2e5f951c6274a91c173449b3e7421 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Bl=C3=A4sing?= Date: Sat, 3 Aug 2019 22:15:34 +0200 Subject: [PATCH 2/2] [GITHUB-1118] Ensure union with floating point and integer member is passed in integer register System V x86-64 ABI requires, that in a union aggregate, that contains Integer and Double members, the parameters must be passed in the integer registers. I.e. in the case where the java side declares double and int members, the wrong FFI Type would be found, because the doubles size is larger than the int member, but the wrong parameter passing method would be used. --- CHANGES.md | 1 + src/com/sun/jna/Native.java | 28 ++-- src/com/sun/jna/Structure.java | 200 ++++++++++++++++---------- test/com/sun/jna/PerformanceTest.java | 32 ++--- test/com/sun/jna/StructureTest.java | 4 +- test/com/sun/jna/UnionTest.java | 8 +- 6 files changed, 165 insertions(+), 108 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 1dcae5f3e..c46580a04 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -16,6 +16,7 @@ Bug Fixes * [#1128](https://github.com/java-native-access/jna/issues/1128): KEY_ALL_ACCESS value is incorrect in `c.s.j.p.win32.WinNT.java` - [@trevormaggs](https://github.com/trevormaggs). * [#1133](https://github.com/java-native-access/jna/issues/1133): Ensure JARs created from the build system don't contain invalid `Info-ZIP Unicode Path` extra info - [@matthiasblaesing](https://github.com/matthiasblaesing). * [#1134](https://github.com/java-native-access/jna/issues/1134): Read correct member of `WinBase.SYSTEM_INFO.processorArchitecture` union - [@dbwiddis](https://github.com/dbwiddis). +* [#1118](https://github.com/java-native-access/jna/issues/1118): Fix passing unions containing integer and floating point members as parameters by value - [@matthiasblaesing](https://github.com/matthiasblaesing). Release 5.4.0 ============= diff --git a/src/com/sun/jna/Native.java b/src/com/sun/jna/Native.java index 39d3a061e..0cf39faf4 100644 --- a/src/com/sun/jna/Native.java +++ b/src/com/sun/jna/Native.java @@ -1770,27 +1770,27 @@ public static void register(Class cls, NativeLibrary lib) { // FFIType.get() always looks up the native type for any given // class, so if we actually have conversion into a Java // object, make sure we use the proper type information - closure_rtype = FFIType.get(rclass.isPrimitive() ? rclass : Pointer.class).peer; - rtype = FFIType.get(fromNative.nativeType()).peer; + closure_rtype = FFIType.get(rclass.isPrimitive() ? rclass : Pointer.class).getPointer().peer; + rtype = FFIType.get(fromNative.nativeType()).getPointer().peer; break; case CVT_NATIVE_MAPPED: case CVT_NATIVE_MAPPED_STRING: case CVT_NATIVE_MAPPED_WSTRING: case CVT_INTEGER_TYPE: case CVT_POINTER_TYPE: - closure_rtype = FFIType.get(Pointer.class).peer; - rtype = FFIType.get(NativeMappedConverter.getInstance(rclass).nativeType()).peer; + closure_rtype = FFIType.get(Pointer.class).getPointer().peer; + rtype = FFIType.get(NativeMappedConverter.getInstance(rclass).nativeType()).getPointer().peer; break; case CVT_STRUCTURE: case CVT_OBJECT: - closure_rtype = rtype = FFIType.get(Pointer.class).peer; + closure_rtype = rtype = FFIType.get(Pointer.class).getPointer().peer; break; case CVT_STRUCTURE_BYVAL: - closure_rtype = FFIType.get(Pointer.class).peer; - rtype = FFIType.get(rclass).peer; + closure_rtype = FFIType.get(Pointer.class).getPointer().peer; + rtype = FFIType.get(rclass).getPointer().peer; break; default: - closure_rtype = rtype = FFIType.get(rclass).peer; + closure_rtype = rtype = FFIType.get(rclass).getPointer().peer; } for (int t=0;t < ptypes.length;t++) { @@ -1822,20 +1822,20 @@ public static void register(Class cls, NativeLibrary lib) { case CVT_NATIVE_MAPPED: case CVT_NATIVE_MAPPED_STRING: case CVT_NATIVE_MAPPED_WSTRING: - atypes[t] = FFIType.get(type).peer; - closure_atypes[t] = FFIType.get(Pointer.class).peer; + atypes[t] = FFIType.get(type).getPointer().peer; + closure_atypes[t] = FFIType.get(Pointer.class).getPointer().peer; break; case CVT_TYPE_MAPPER: case CVT_TYPE_MAPPER_STRING: case CVT_TYPE_MAPPER_WSTRING: - closure_atypes[t] = FFIType.get(type.isPrimitive() ? type : Pointer.class).peer; - atypes[t] = FFIType.get(toNative[t].nativeType()).peer; + closure_atypes[t] = FFIType.get(type.isPrimitive() ? type : Pointer.class).getPointer().peer; + atypes[t] = FFIType.get(toNative[t].nativeType()).getPointer().peer; break; case CVT_DEFAULT: - closure_atypes[t] = atypes[t] = FFIType.get(type).peer; + closure_atypes[t] = atypes[t] = FFIType.get(type).getPointer().peer; break; default: - closure_atypes[t] = atypes[t] = FFIType.get(Pointer.class).peer; + closure_atypes[t] = atypes[t] = FFIType.get(Pointer.class).getPointer().peer; } } sig += ")"; diff --git a/src/com/sun/jna/Structure.java b/src/com/sun/jna/Structure.java index 8a009fc63..4cb2c132e 100644 --- a/src/com/sun/jna/Structure.java +++ b/src/com/sun/jna/Structure.java @@ -1191,8 +1191,6 @@ private static class LayoutInfo { private int alignType = ALIGN_DEFAULT; private TypeMapper typeMapper; private boolean variable; - // For unions only, field on which the union FFI type info is based - private StructField typeInfoField; } private void validateField(String name, Class type) { @@ -1353,13 +1351,6 @@ else if (writeConverter != null || readConverter != null) { // Save the field in our list info.fields.put(structField.name, structField); - - if (info.typeInfoField == null - || info.typeInfoField.size < structField.size - || (info.typeInfoField.size == structField.size - && Structure.class.isAssignableFrom(structField.type))) { - info.typeInfoField = structField; - } } if (calculatedSize > 0) { @@ -1728,7 +1719,7 @@ protected void cacheTypeInfo(Pointer p) { * @param f internal field representation * @return Native pointer to the corresponding type information */ - Pointer getFieldTypeInfo(StructField f) { + FFIType getFieldTypeInfo(StructField f) { Class type = f.type; Object value = getFieldValue(f.field); if (typeMapper != null) { @@ -1745,7 +1736,7 @@ Pointer getFieldTypeInfo(StructField f) { * @return native type information for this structure. */ Pointer getTypeInfo() { - Pointer p = getTypeInfo(this); + Pointer p = getTypeInfo(this).getPointer(); cacheTypeInfo(p); return p; } @@ -1811,7 +1802,7 @@ public boolean getAutoWrite() { * @param obj object to query * @return native pointer to type information */ - static Pointer getTypeInfo(Object obj) { + static FFIType getTypeInfo(Object obj) { return FFIType.get(obj); } @@ -1884,21 +1875,6 @@ public static T newInstance(Class type) throws IllegalA return s; } - /** Keep track of the largest aggregate field of the union to use for - * FFI type information. - * @return which field to use to obtain FFI type information - */ - StructField typeInfoField() { - LayoutInfo info; - synchronized(layoutInfo) { - info = layoutInfo.get(getClass()); - } - if (info != null) { - return info.typeInfoField; - } - return null; - } - /** * Returns a constructor for the given type with a single Pointer argument, null if no such constructor is found. * @param type the class @@ -1932,7 +1908,8 @@ public String toString() { return name + "@" + offset + "[" + size + "] (" + type + ")"; } } - /** This class auto-generates an ffi_type structure appropriate for a given + /** + * This class auto-generates an ffi_type structure appropriate for a given * structure for use by libffi. The lifecycle of this structure is easier * to manage on the Java side than in native code. */ @@ -1945,7 +1922,9 @@ public static class size_t extends IntegerType { public size_t(long value) { super(Native.SIZE_T_SIZE, value); } } - private static final Map typeInfoMap = new WeakHashMap(); + private static final Map typeInfoMap = new WeakHashMap(); + private static final Map unionHelper = new WeakHashMap(); + private static final Map ffiTypeInfo = new HashMap(); // Native.initIDs initializes these fields to their appropriate // pointer values. These are in a separate class from FFIType so that @@ -1966,34 +1945,69 @@ private static class FFITypes { private static Pointer ffi_type_pointer; } + private static boolean isIntegerType(FFIType type) { + Pointer typePointer = type.getPointer(); + return typePointer.equals(FFITypes.ffi_type_uint8) + || typePointer.equals(FFITypes.ffi_type_sint8) + || typePointer.equals(FFITypes.ffi_type_uint16) + || typePointer.equals(FFITypes.ffi_type_sint16) + || typePointer.equals(FFITypes.ffi_type_uint32) + || typePointer.equals(FFITypes.ffi_type_sint32) + || typePointer.equals(FFITypes.ffi_type_uint64) + || typePointer.equals(FFITypes.ffi_type_sint64) + || typePointer.equals(FFITypes.ffi_type_pointer); + } + + private static boolean isFloatType(FFIType type) { + Pointer typePointer = type.getPointer(); + return typePointer.equals(FFITypes.ffi_type_float) + || typePointer.equals(FFITypes.ffi_type_double); + } + static { if (Native.POINTER_SIZE == 0) throw new Error("Native library not initialized"); if (FFITypes.ffi_type_void == null) throw new Error("FFI types not initialized"); - typeInfoMap.put(void.class, FFITypes.ffi_type_void); - typeInfoMap.put(Void.class, FFITypes.ffi_type_void); - typeInfoMap.put(float.class, FFITypes.ffi_type_float); - typeInfoMap.put(Float.class, FFITypes.ffi_type_float); - typeInfoMap.put(double.class, FFITypes.ffi_type_double); - typeInfoMap.put(Double.class, FFITypes.ffi_type_double); - typeInfoMap.put(long.class, FFITypes.ffi_type_sint64); - typeInfoMap.put(Long.class, FFITypes.ffi_type_sint64); - typeInfoMap.put(int.class, FFITypes.ffi_type_sint32); - typeInfoMap.put(Integer.class, FFITypes.ffi_type_sint32); - typeInfoMap.put(short.class, FFITypes.ffi_type_sint16); - typeInfoMap.put(Short.class, FFITypes.ffi_type_sint16); - Pointer ctype = Native.WCHAR_SIZE == 2 - ? FFITypes.ffi_type_uint16 : FFITypes.ffi_type_uint32; + ffiTypeInfo.put(FFITypes.ffi_type_void, Structure.newInstance(FFIType.class, FFITypes.ffi_type_void)); + ffiTypeInfo.put(FFITypes.ffi_type_float, Structure.newInstance(FFIType.class, FFITypes.ffi_type_float)); + ffiTypeInfo.put(FFITypes.ffi_type_double, Structure.newInstance(FFIType.class, FFITypes.ffi_type_double)); + ffiTypeInfo.put(FFITypes.ffi_type_longdouble, Structure.newInstance(FFIType.class, FFITypes.ffi_type_longdouble)); + ffiTypeInfo.put(FFITypes.ffi_type_uint8, Structure.newInstance(FFIType.class, FFITypes.ffi_type_uint8)); + ffiTypeInfo.put(FFITypes.ffi_type_sint8, Structure.newInstance(FFIType.class, FFITypes.ffi_type_sint8)); + ffiTypeInfo.put(FFITypes.ffi_type_uint16, Structure.newInstance(FFIType.class, FFITypes.ffi_type_uint16)); + ffiTypeInfo.put(FFITypes.ffi_type_sint16, Structure.newInstance(FFIType.class, FFITypes.ffi_type_sint16)); + ffiTypeInfo.put(FFITypes.ffi_type_uint32, Structure.newInstance(FFIType.class, FFITypes.ffi_type_uint32)); + ffiTypeInfo.put(FFITypes.ffi_type_sint32, Structure.newInstance(FFIType.class, FFITypes.ffi_type_sint32)); + ffiTypeInfo.put(FFITypes.ffi_type_uint64, Structure.newInstance(FFIType.class, FFITypes.ffi_type_uint64)); + ffiTypeInfo.put(FFITypes.ffi_type_sint64, Structure.newInstance(FFIType.class, FFITypes.ffi_type_sint64)); + ffiTypeInfo.put(FFITypes.ffi_type_pointer, Structure.newInstance(FFIType.class, FFITypes.ffi_type_pointer)); + for(FFIType f: ffiTypeInfo.values()) { + f.read(); + } + typeInfoMap.put(void.class, ffiTypeInfo.get(FFITypes.ffi_type_void)); + typeInfoMap.put(Void.class, ffiTypeInfo.get(FFITypes.ffi_type_void)); + typeInfoMap.put(float.class, ffiTypeInfo.get(FFITypes.ffi_type_float)); + typeInfoMap.put(Float.class, ffiTypeInfo.get(FFITypes.ffi_type_float)); + typeInfoMap.put(double.class, ffiTypeInfo.get(FFITypes.ffi_type_double)); + typeInfoMap.put(Double.class, ffiTypeInfo.get(FFITypes.ffi_type_double)); + typeInfoMap.put(long.class, ffiTypeInfo.get(FFITypes.ffi_type_sint64)); + typeInfoMap.put(Long.class, ffiTypeInfo.get(FFITypes.ffi_type_sint64)); + typeInfoMap.put(int.class, ffiTypeInfo.get(FFITypes.ffi_type_sint32)); + typeInfoMap.put(Integer.class, ffiTypeInfo.get(FFITypes.ffi_type_sint32)); + typeInfoMap.put(short.class, ffiTypeInfo.get(FFITypes.ffi_type_sint16)); + typeInfoMap.put(Short.class, ffiTypeInfo.get(FFITypes.ffi_type_sint16)); + FFIType ctype = Native.WCHAR_SIZE == 2 + ? ffiTypeInfo.get(FFITypes.ffi_type_uint16) : ffiTypeInfo.get(FFITypes.ffi_type_uint32); typeInfoMap.put(char.class, ctype); typeInfoMap.put(Character.class, ctype); - typeInfoMap.put(byte.class, FFITypes.ffi_type_sint8); - typeInfoMap.put(Byte.class, FFITypes.ffi_type_sint8); - typeInfoMap.put(Pointer.class, FFITypes.ffi_type_pointer); - typeInfoMap.put(String.class, FFITypes.ffi_type_pointer); - typeInfoMap.put(WString.class, FFITypes.ffi_type_pointer); - typeInfoMap.put(boolean.class, FFITypes.ffi_type_uint32); - typeInfoMap.put(Boolean.class, FFITypes.ffi_type_uint32); + typeInfoMap.put(byte.class, ffiTypeInfo.get(FFITypes.ffi_type_sint8)); + typeInfoMap.put(Byte.class, ffiTypeInfo.get(FFITypes.ffi_type_sint8)); + typeInfoMap.put(Pointer.class, ffiTypeInfo.get(FFITypes.ffi_type_pointer)); + typeInfoMap.put(String.class, ffiTypeInfo.get(FFITypes.ffi_type_pointer)); + typeInfoMap.put(WString.class, ffiTypeInfo.get(FFITypes.ffi_type_pointer)); + typeInfoMap.put(boolean.class, ffiTypeInfo.get(FFITypes.ffi_type_uint32)); + typeInfoMap.put(Boolean.class, ffiTypeInfo.get(FFITypes.ffi_type_uint32)); } // From ffi.h private static final int FFI_TYPE_STRUCT = 13; @@ -2003,35 +2017,80 @@ private static class FFITypes { public short type = FFI_TYPE_STRUCT; public Pointer elements; - private FFIType(Structure ref) { + public FFIType(FFIType reference) { + this.size = reference.size; + this.alignment = reference.alignment; + this.type = reference.type; + this.elements = reference.elements; + } + + public FFIType() {} + + public FFIType(Structure ref) { Pointer[] els; ref.ensureAllocated(true); if (ref instanceof Union) { - StructField sf = ((Union)ref).typeInfoField(); + FFIType unionType = null; + int size = 0; + boolean hasInteger = false; + for (StructField sf : ref.fields().values()) { + FFIType type = ref.getFieldTypeInfo(sf); + if (isIntegerType(type)) { + hasInteger = true; + } + if (unionType == null + || size < sf.size + || (size == sf.size + && Structure.class.isAssignableFrom(sf.type))) { + unionType = type; + size = sf.size; + } + } + if((! Platform.isWindows()) && Platform.isIntel() && Platform.is64Bit()) { + // System V x86-64 ABI requires, that in a union aggregate, + // that contains Integer and Double members, the parameters + // must be passed in the integer registers. I.e. in the case + // where the java side declares double and int members, the + // wrong FFI Type would be found, because the doubles size + // is larger than the int member, but the wrong parameter + // passing method would be used. + if(hasInteger && isFloatType(unionType)) { + unionType = new FFIType(unionType); + if(unionType.size.intValue() == 4) { + unionType.type = ffiTypeInfo.get(FFITypes.ffi_type_uint32).type; + } else if (unionType.size.intValue() == 8) { + unionType.type = ffiTypeInfo.get(FFITypes.ffi_type_uint64).type; + } + unionType.write(); + } + } els = new Pointer[] { - get(ref.getFieldValue(sf.field), sf.type), + unionType.getPointer(), null, }; + unionHelper.put(ref.getClass(), unionType); } else { els = new Pointer[ref.fields().size() + 1]; int idx = 0; for (StructField sf : ref.fields().values()) { - els[idx++] = ref.getFieldTypeInfo(sf); + els[idx++] = ref.getFieldTypeInfo(sf).getPointer(); } } init(els); + write(); } // Represent fixed-size arrays as structures of N identical elements - private FFIType(Object array, Class type) { + public FFIType(Object array, Class type) { int length = Array.getLength(array); Pointer[] els = new Pointer[length+1]; - Pointer p = get(null, type.getComponentType()); + Pointer p = get(null, type.getComponentType()).getPointer(); for (int i=0;i < length;i++) { els[i] = p; } init(els); + write(); } private void init(Pointer[] els) { @@ -2041,15 +2100,15 @@ private void init(Pointer[] els) { } /** Obtain a pointer to the native FFI type descriptor for the given object. */ - static Pointer get(Object obj) { + static FFIType get(Object obj) { if (obj == null) - return FFITypes.ffi_type_pointer; + return typeInfoMap.get(Pointer.class); if (obj instanceof Class) return get(null, (Class)obj); return get(obj, obj.getClass()); } - private static Pointer get(Object obj, Class cls) { + private static FFIType get(Object obj, Class cls) { TypeMapper mapper = Native.getTypeMapper(cls); if (mapper != null) { ToNativeConverter nc = mapper.getToNativeConverter(cls); @@ -2058,27 +2117,24 @@ private static Pointer get(Object obj, Class cls) { } } synchronized(typeInfoMap) { - Object o = typeInfoMap.get(cls); - if (o instanceof Pointer) { - return (Pointer)o; - } - if (o instanceof FFIType) { - return ((FFIType)o).getPointer(); + FFIType o = typeInfoMap.get(cls); + if (o != null) { + return o; } if ((Platform.HAS_BUFFERS && Buffer.class.isAssignableFrom(cls)) || Callback.class.isAssignableFrom(cls)) { - typeInfoMap.put(cls, FFITypes.ffi_type_pointer); - return FFITypes.ffi_type_pointer; + typeInfoMap.put(cls, typeInfoMap.get(Pointer.class)); + return typeInfoMap.get(Pointer.class); } if (Structure.class.isAssignableFrom(cls)) { if (obj == null) obj = newInstance((Class) cls, PLACEHOLDER_MEMORY); if (ByReference.class.isAssignableFrom(cls)) { - typeInfoMap.put(cls, FFITypes.ffi_type_pointer); - return FFITypes.ffi_type_pointer; + typeInfoMap.put(cls, typeInfoMap.get(Pointer.class)); + return typeInfoMap.get(Pointer.class); } FFIType type = new FFIType((Structure)obj); typeInfoMap.put(cls, type); - return type.getPointer(); + return type; } if (NativeMapped.class.isAssignableFrom(cls)) { NativeMappedConverter c = NativeMappedConverter.getInstance(cls); @@ -2087,8 +2143,8 @@ private static Pointer get(Object obj, Class cls) { if (cls.isArray()) { FFIType type = new FFIType(obj, cls); // Store it in the map to prevent premature GC of type info - typeInfoMap.put(obj, type); - return type.getPointer(); + typeInfoMap.put(cls, type); + return type; } throw new IllegalArgumentException("Unsupported type " + cls); } diff --git a/test/com/sun/jna/PerformanceTest.java b/test/com/sun/jna/PerformanceTest.java index f212f3f27..329283c92 100644 --- a/test/com/sun/jna/PerformanceTest.java +++ b/test/com/sun/jna/PerformanceTest.java @@ -163,8 +163,8 @@ public static void checkPerformance() { 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); + b.putInt(0, (int)Structure.FFIType.get(double.class).getPointer().peer); + cif = Native.ffi_prep_cif(0, 1, Structure.FFIType.get(double.class).getPointer().peer, types); resp = pb.peer + 4; argv = pb.peer + 12; double INPUT = 42; @@ -178,8 +178,8 @@ public static void checkPerformance() { 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); + b.putLong(0, Structure.FFIType.get(double.class).getPointer().peer); + cif = Native.ffi_prep_cif(0, 1, Structure.FFIType.get(double.class).getPointer().peer, types); resp = pb.peer + 8; argv = pb.peer + 16; double INPUT = 42; @@ -305,10 +305,10 @@ public String getFunctionName(NativeLibrary library, Method method) { 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); + b.putInt(0, (int)Structure.FFIType.get(Pointer.class).getPointer().peer); + b.putInt(4, (int)Structure.FFIType.get(int.class).getPointer().peer); + b.putInt(8, (int)Structure.FFIType.get(int.class).getPointer().peer); + cif = Native.ffi_prep_cif(0, 3, Structure.FFIType.get(Pointer.class).getPointer().peer, types); resp = pb.peer + 12; argv = pb.peer + 16; start = System.currentTimeMillis(); @@ -325,10 +325,10 @@ public String getFunctionName(NativeLibrary library, Method method) { 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); + b.putLong(0, Structure.FFIType.get(Pointer.class).getPointer().peer); + b.putLong(8, Structure.FFIType.get(int.class).getPointer().peer); + b.putLong(16, Structure.FFIType.get(long.class).getPointer().peer); + cif = Native.ffi_prep_cif(0, 3, Structure.FFIType.get(Pointer.class).getPointer().peer, types); resp = pb.peer + 24; argv = pb.peer + 32; start = System.currentTimeMillis(); @@ -405,8 +405,8 @@ public String getFunctionName(NativeLibrary library, Method method) { 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); + b.putInt(0, (int)Structure.FFIType.get(Pointer.class).getPointer().peer); + cif = Native.ffi_prep_cif(0, 1, Structure.FFIType.get(int.class).getPointer().peer, types); resp = pb.peer + 4; argv = pb.peer + 8; start = System.currentTimeMillis(); @@ -423,8 +423,8 @@ public String getFunctionName(NativeLibrary library, Method method) { 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); + b.putLong(0, Structure.FFIType.get(Pointer.class).getPointer().peer); + cif = Native.ffi_prep_cif(0, 1, Structure.FFIType.get(long.class).getPointer().peer, types); resp = pb.peer + 8; argv = pb.peer + 16; start = System.currentTimeMillis(); diff --git a/test/com/sun/jna/StructureTest.java b/test/com/sun/jna/StructureTest.java index 449bc07bc..db7c1aeac 100644 --- a/test/com/sun/jna/StructureTest.java +++ b/test/com/sun/jna/StructureTest.java @@ -1388,7 +1388,7 @@ public void testNestedStructureTypeInfo() { assertEquals("Wrong type information for 'inner' field", inner, els.getPointer(0)); assertEquals("Wrong type information for integer field", - Structure.getTypeInfo(Integer.valueOf(0)), + Structure.getTypeInfo(0).getPointer(), els.getPointer(Native.POINTER_SIZE)); assertNull("Type element list should be null-terminated", els.getPointer(Native.POINTER_SIZE*2)); @@ -2163,7 +2163,7 @@ protected List getFieldOrder() { Structure s = new TestStructure(); assertEquals("Wrong type mapper for structure", mapper, s.getTypeMapper()); - TestFFIType ffi_type = new TestFFIType(Structure.getTypeInfo(s)); + TestFFIType ffi_type = new TestFFIType(Structure.getTypeInfo(s).getPointer()); assertEquals("Java Structure size does not match FFIType size", s.size(), ffi_type.size.intValue()); } diff --git a/test/com/sun/jna/UnionTest.java b/test/com/sun/jna/UnionTest.java index 314e781c7..c960c5a38 100644 --- a/test/com/sun/jna/UnionTest.java +++ b/test/com/sun/jna/UnionTest.java @@ -171,12 +171,12 @@ public void testReadTypeInfo() { assertNotNull("Type information is missing for union instance", u.getTypeInfo()); if (Native.POINTER_SIZE == 4) { assertEquals("Type size should be that of largest field if no field is active", - Structure.getTypeInfo(BigTestStructure.class).getInt(0), + Structure.getTypeInfo(BigTestStructure.class).getPointer().getInt(0), u.getTypeInfo().getInt(0)); } else { assertEquals("Type size should be that of largest field if no field is active", - Structure.getTypeInfo(BigTestStructure.class).getLong(0), + Structure.getTypeInfo(BigTestStructure.class).getPointer().getLong(0), u.getTypeInfo().getLong(0)); } u.setType(int.class); @@ -184,12 +184,12 @@ public void testReadTypeInfo() { assertNotNull("Type information is missing for union instance after type set", u.getTypeInfo()); if (Native.POINTER_SIZE == 4) { assertEquals("Type size should be that of largest field if any field is active", - Structure.getTypeInfo(BigTestStructure.class).getInt(0), + Structure.getTypeInfo(BigTestStructure.class).getPointer().getInt(0), u.getTypeInfo().getInt(0)); } else { assertEquals("Type size should be that of largest field if any field is active", - Structure.getTypeInfo(BigTestStructure.class).getLong(0), + Structure.getTypeInfo(BigTestStructure.class).getPointer().getLong(0), u.getTypeInfo().getLong(0)); } }