From a0b8dcccdba3a595bd6b77cf60b0644a1dc0f2a1 Mon Sep 17 00:00:00 2001 From: zhanhb Date: Fri, 20 Oct 2017 22:44:46 +0800 Subject: [PATCH 1/4] Add align test --- src/test/java/jnr/ffi/StructTest.java | 325 ++++++++++++++++++++++++++ 1 file changed, 325 insertions(+) create mode 100644 src/test/java/jnr/ffi/StructTest.java diff --git a/src/test/java/jnr/ffi/StructTest.java b/src/test/java/jnr/ffi/StructTest.java new file mode 100644 index 000000000..cd307a280 --- /dev/null +++ b/src/test/java/jnr/ffi/StructTest.java @@ -0,0 +1,325 @@ +package jnr.ffi; + +import static org.junit.Assert.assertEquals; +import org.junit.Test; + +public class StructTest { + + public static class A extends Struct { + private Signed32 x = new Signed32(); + private Signed8 y = new Signed8(); + public A(jnr.ffi.Runtime runtime) { + super(runtime); + } + } + public static class B extends Struct { + private Signed8 x = new Signed8(); + private Signed32 y = new Signed32(); + public B(jnr.ffi.Runtime runtime) { + super(runtime); + } + } + public static class C extends Struct { + private Signed8 x = new Signed8(); + private Signed8 y = new Signed8(); + private Signed32 z = new Signed32(); + public C(jnr.ffi.Runtime runtime) { + super(runtime); + } + } + public static class D extends Struct { + private Signed8 x = new Signed8(); + private Signed64 y = new Signed64(); + private Signed32 z = new Signed32(); + public D(jnr.ffi.Runtime runtime) { + super(runtime); + } + } + public static class E extends Struct { + private Signed8 x = new Signed8(); + private D y = inner(new D(getRuntime())); + public E(jnr.ffi.Runtime runtime) { + super(runtime); + } + } + public static class Array1 extends Struct { + private D[] t = array(new D[3]); + public Array1(jnr.ffi.Runtime runtime) { + super(runtime); + } + } + public static class LARGE_INTEGER_PART extends Struct { + private Unsigned32 LowPart = new Unsigned32(); + private Signed32 HighPart = new Signed32(); + public LARGE_INTEGER_PART(jnr.ffi.Runtime runtime) { + super(runtime); + } + } + public static class MyLargeInteger extends Union { // union + private LARGE_INTEGER_PART u = inner(new LARGE_INTEGER_PART(getRuntime())); + private Signed64 QuadPart = new Signed64(); + public MyLargeInteger(jnr.ffi.Runtime runtime) { + super(runtime); + } + } + public static class F extends Struct { + private Signed32 x = new Signed32(); + private MyLargeInteger y = inner(new MyLargeInteger(getRuntime())); + public F(jnr.ffi.Runtime runtime) { + super(runtime); + } + } + public static class G extends Struct { + private Signed8 x = new Signed8(); + private MyLargeInteger y = inner(new MyLargeInteger(getRuntime())); + private Signed32 z = new Signed32(); + public G(jnr.ffi.Runtime runtime) { + super(runtime); + } + } + public static class Array2 extends Struct { + private G[] t = array(new G[3]); + Array2(jnr.ffi.Runtime runtime) { + super(runtime); + } + } + public static class Union1 extends Union { + private Signed32[] intVal = array(new Signed32[2]); + private Signed8[] ch = array(new Signed8[8]); + private MyLargeInteger my = inner(new MyLargeInteger(getRuntime())); + private Signed16[] ss = array(new Signed16[4]); + private Signed64 u = new Signed64(); + public Union1(jnr.ffi.Runtime runtime) { + super(runtime); + } + } + public static class H extends Struct { + private Signed8[] x = array(new Signed8[3]); + public H(Runtime runtime) { + super(runtime); + } + } + public static class Union2 extends Union { + private H[] x = array(new H[5]); + public Union2(Runtime runtime) { + super(runtime); + } + } + public static class J extends Struct { + private Signed16 x = new Signed16(); + private Signed8[] y = array(new Signed8[3]); + public J(Runtime runtime) { + super(runtime); + } + } + public static class Union3 extends Union { + private J[] x = array(new J[5]); + private Signed8[] y = array(new Signed8[13]); + public Union3(Runtime runtime) { + super(runtime); + } + } + + private static final jnr.ffi.Runtime runtime = jnr.ffi.Runtime.getSystemRuntime(); + + @Test + public void testAlignA() { + test(new A(runtime), 4, 8); + } + + @Test + public void testAlignB() { + test(new B(runtime), 4, 8); + } + + @Test + public void testAlignC() { + test(new C(runtime), 4, 8); + } + + @Test + public void testAlignD() { + test(new D(runtime), 8, 24); + } + + @Test + public void testAlignE() { + test(new E(runtime), 8, 32); + } + + @Test + public void testAlignArray1() { + test(new Array1(runtime), 8, 72); + } + + @Test + public void testAlignMyLargeInteger() { + test(new MyLargeInteger(runtime), 8, 8); + } + + @Test + public void testAlignF() { + test(new F(runtime), 8, 16); + } + + @Test + public void testAlignG() { + test(new G(runtime), 8, 24); + } + + @Test + public void testAlignArray2() { + test(new Array2(runtime), 8, 72); + } + + @Test + public void testAlignUnion1() { + test(new Union1(runtime), 8, 8); + } + + @Test + public void testAlignH() { + test(new H(runtime), 1, 3); + } + + @Test + public void testAlignUnion2() { + test(new Union2(runtime), 1, 15); + } + + @Test + public void testAlignJ() { + test(new J(runtime), 2, 6); + } + + @Test + public void testAlignUnion3() { + test(new Union3(runtime), 2, 30); + } + + private void test(Struct a, int alignment, int sizeof) { + String name = a.getClass().getSimpleName(); + assertEquals(name + ".alignment()", alignment, Struct.alignment(a)); + assertEquals("sizeof(" + name + ")", sizeof, sizeof(a)); + } + + private int sizeof(Struct struct) { + int size = Struct.size(struct); + int align = Struct.alignment(struct); + return (size + align - 1) & -align; + } + +} +/* +#include +#include + +struct A { + int x; + char y; +}; + +struct B { + char x; + int y; +}; + +struct C { + char x; + char y; + int z; +}; + +struct D { + char x; + long long y; + int z; +}; + +struct E { + char x; + D y; +}; + +struct Array1 { + D t[3]; +}; + +union MyLargeInteger { + + struct { + unsigned int LowPart; + int HighPart; + } u; + long long QuadPart; +}; + +struct F { + int x; + MyLargeInteger y; +}; + +struct G { + char x; + MyLargeInteger y; + int z; +}; + +struct Array2 { + G t[3]; +}; + +union Union1 { + int intVal[2]; + char ch[8]; + MyLargeInteger my; + short ss[4]; + long long u; +}; + +struct H { + char x[3]; +}; + +struct Union2 { + H x[5]; +}; + +struct J { + short x; + char y[3]; +}; + +union Union3 { + J x[5]; + char y[13]; +}; + +#define DUMP(type) \ +do{ \ +typedef struct _AlignType##type { \ + char c; \ + type d; \ +} AlignType##type; \ +printf("@Test\npublic void testAlign%s() {\ntest(new %s(runtime), %d, %d);\n}\n", #type, #type, offsetof(AlignType##type, d), sizeof(type));\ +} while(0) + +int main() { + DUMP(A); + DUMP(B); + DUMP(C); + DUMP(D); + DUMP(E); + DUMP(Array1); + DUMP(MyLargeInteger); + DUMP(F); + DUMP(G); + DUMP(Array2); + DUMP(Union1); + DUMP(H); + DUMP(Union2); + DUMP(J); + DUMP(Union3); +} + +*/ From b47c65b431e38054c737a9183a2653270c211399 Mon Sep 17 00:00:00 2001 From: zhanhb Date: Sat, 21 Oct 2017 22:20:29 +0800 Subject: [PATCH 2/4] Fix alignment for nested types --- src/main/java/jnr/ffi/Struct.java | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/main/java/jnr/ffi/Struct.java b/src/main/java/jnr/ffi/Struct.java index f235472cb..33cbadb60 100755 --- a/src/main/java/jnr/ffi/Struct.java +++ b/src/main/java/jnr/ffi/Struct.java @@ -53,7 +53,7 @@ static final class Info { int size = 0; int minAlign = 1; boolean isUnion = false; - boolean resetIndex = false; + int currentSize = -1; // only used when this is an enum and add array elements Alignment alignment = new Alignment(0); @@ -93,6 +93,20 @@ private jnr.ffi.Pointer allocateMemory(int flags) { } } + private int nextOffset(int size, int alignment) { + if (isUnion) { + if (currentSize > -1) { // add element to an array + int result = align(this.currentSize, alignment); + this.currentSize = result + size; + return result; + } else { + return 0; + } + } else { + return align(this.size, alignment); + } + } + public final void useMemory(jnr.ffi.Pointer io) { this.memory = io; } @@ -105,7 +119,7 @@ protected final int addField(int sizeBits, int alignBits, Offset offset) { protected final int addField(int sizeBits, int alignBits) { final int alignment = this.alignment.intValue() > 0 ? Math.min(this.alignment.intValue(), (alignBits >> 3)) : (alignBits >> 3); - final int offset = resetIndex ? 0 : align(this.size, alignment); + final int offset = nextOffset(sizeBits >> 3, alignment); this.size = Math.max(this.size, offset + (sizeBits >> 3)); this.minAlign = Math.max(this.minAlign, alignment); return offset; @@ -139,7 +153,7 @@ protected Struct(Runtime runtime, Struct enclosing) { */ protected Struct(Runtime runtime, final boolean isUnion) { this(runtime); - __info.resetIndex = isUnion; + __info.currentSize = -1; __info.isUnion = isUnion; } @@ -314,14 +328,14 @@ protected abstract class Member { * Starts an array construction session */ protected final void arrayBegin() { - __info.resetIndex = false; + __info.currentSize = 0; } /** * Ends an array construction session */ protected final void arrayEnd() { - __info.resetIndex = __info.isUnion; + __info.currentSize = -1; } /** @@ -684,10 +698,11 @@ protected UTF8String[] array(UTF8String[] array, int stringLength) { protected final T inner(T struct) { int alignment = __info.alignment.intValue() > 0 ? Math.min(__info.alignment.intValue(), struct.__info.getMinimumAlignment()) : struct.__info.getMinimumAlignment(); - int offset = __info.resetIndex ? 0 : align(__info.size, alignment); + int offset = __info.nextOffset(struct.__info.size, alignment); struct.__info.enclosing = this; struct.__info.offset = offset; __info.size = Math.max(__info.size, offset + struct.__info.size); + __info.minAlign = Math.max(__info.minAlign, alignment); return struct; } From 0a52632bdb13e36bd65f35b45e267f54b50c4265 Mon Sep 17 00:00:00 2001 From: zhanhb Date: Sun, 22 Oct 2017 00:00:16 +0800 Subject: [PATCH 3/4] Improve the test compatible with different platforms --- libtest/StructNestedTest.c | 129 ++++++++++++++++++++ src/test/java/jnr/ffi/StructTest.java | 162 +++++--------------------- 2 files changed, 161 insertions(+), 130 deletions(-) create mode 100644 libtest/StructNestedTest.c diff --git a/libtest/StructNestedTest.c b/libtest/StructNestedTest.c new file mode 100644 index 000000000..0d59ea95a --- /dev/null +++ b/libtest/StructNestedTest.c @@ -0,0 +1,129 @@ +#include +#include +#include + +typedef struct _A { + int x; + char y; +} A; + +typedef struct _B { + char x; + int y; +} B; + +typedef struct _C { + char x; + char y; + int z; +} C; + +typedef struct _D { + char x; + long long y; + int z; +} D; + +typedef struct _E { + char x; + D y; +} E; + +typedef struct _Array1 { + D t[3]; +} Array1; + +typedef union _MyLargeInteger { + + struct { + unsigned int LowPart; + int HighPart; + } u; + long long QuadPart; +} MyLargeInteger; + +typedef struct _F { + int x; + MyLargeInteger y; +} F; + +typedef struct _G { + char x; + MyLargeInteger y; + int z; +} G; + +typedef struct _Array2 { + G t[3]; +} Array2; + +typedef union _Union1 { + int intVal[2]; + char ch[8]; + MyLargeInteger my; + short ss[4]; + long long u; +} Union1; + +typedef struct _H { + char x[3]; +} H; + +typedef union _Union2 { + H x[5]; +} Union2; + +typedef struct _J { + short x; + char y[3]; +} J; + +typedef union _Union3 { + J x[5]; + char y[13]; +} Union3; + +struct Result { + int align; + int size; +}; + +#define DUMP(type) \ +do { \ +typedef struct _AlignType##type { \ + char c; \ + type d; \ +} AlignType##type; \ +if(strcmp(#type,name)==0){ \ + res.align = offsetof(AlignType##type, d); \ + res.size = sizeof(type); \ +} \ +} while(0) + +static struct Result getTypeDescription(const char * name) { + struct Result res = {0, 0}; + DUMP(A); + DUMP(B); + DUMP(C); + DUMP(D); + DUMP(E); + DUMP(Array1); + DUMP(MyLargeInteger); + DUMP(F); + DUMP(G); + DUMP(Array2); + DUMP(Union1); + DUMP(H); + DUMP(Union2); + DUMP(J); + DUMP(Union3); + return res; +} + +int getTypeSize(const char * name) { + return getTypeDescription(name).size; +} + +int getTypeAlign(const char * name) { + return getTypeDescription(name).align; +} diff --git a/src/test/java/jnr/ffi/StructTest.java b/src/test/java/jnr/ffi/StructTest.java index cd307a280..8162f89e9 100644 --- a/src/test/java/jnr/ffi/StructTest.java +++ b/src/test/java/jnr/ffi/StructTest.java @@ -1,10 +1,15 @@ package jnr.ffi; import static org.junit.Assert.assertEquals; +import org.junit.BeforeClass; import org.junit.Test; public class StructTest { + public static interface TestLib { + int getTypeSize(String type); + int getTypeAlign(String type); + } public static class A extends Struct { private Signed32 x = new Signed32(); private Signed8 y = new Signed8(); @@ -120,85 +125,95 @@ public Union3(Runtime runtime) { } } - private static final jnr.ffi.Runtime runtime = jnr.ffi.Runtime.getSystemRuntime(); + private static jnr.ffi.Runtime runtime; + + static TestLib testlib; + + @BeforeClass + public static void setUpClass() { + testlib = TstUtil.loadTestLib(TestLib.class); + runtime = jnr.ffi.Runtime.getRuntime(testlib); + } @Test public void testAlignA() { - test(new A(runtime), 4, 8); + test(new A(runtime)); } @Test public void testAlignB() { - test(new B(runtime), 4, 8); + test(new B(runtime)); } @Test public void testAlignC() { - test(new C(runtime), 4, 8); + test(new C(runtime)); } @Test public void testAlignD() { - test(new D(runtime), 8, 24); + test(new D(runtime)); } @Test public void testAlignE() { - test(new E(runtime), 8, 32); + test(new E(runtime)); } @Test public void testAlignArray1() { - test(new Array1(runtime), 8, 72); + test(new Array1(runtime)); } @Test public void testAlignMyLargeInteger() { - test(new MyLargeInteger(runtime), 8, 8); + test(new MyLargeInteger(runtime)); } @Test public void testAlignF() { - test(new F(runtime), 8, 16); + test(new F(runtime)); } @Test public void testAlignG() { - test(new G(runtime), 8, 24); + test(new G(runtime)); } @Test public void testAlignArray2() { - test(new Array2(runtime), 8, 72); + test(new Array2(runtime)); } @Test public void testAlignUnion1() { - test(new Union1(runtime), 8, 8); + test(new Union1(runtime)); } @Test public void testAlignH() { - test(new H(runtime), 1, 3); + test(new H(runtime)); } @Test public void testAlignUnion2() { - test(new Union2(runtime), 1, 15); + test(new Union2(runtime)); } @Test public void testAlignJ() { - test(new J(runtime), 2, 6); + test(new J(runtime)); } @Test public void testAlignUnion3() { - test(new Union3(runtime), 2, 30); + test(new Union3(runtime)); } - private void test(Struct a, int alignment, int sizeof) { + private void test(Struct a) { String name = a.getClass().getSimpleName(); + int alignment = testlib.getTypeAlign(name); + int sizeof = testlib.getTypeSize(name); assertEquals(name + ".alignment()", alignment, Struct.alignment(a)); assertEquals("sizeof(" + name + ")", sizeof, sizeof(a)); } @@ -210,116 +225,3 @@ private int sizeof(Struct struct) { } } -/* -#include -#include - -struct A { - int x; - char y; -}; - -struct B { - char x; - int y; -}; - -struct C { - char x; - char y; - int z; -}; - -struct D { - char x; - long long y; - int z; -}; - -struct E { - char x; - D y; -}; - -struct Array1 { - D t[3]; -}; - -union MyLargeInteger { - - struct { - unsigned int LowPart; - int HighPart; - } u; - long long QuadPart; -}; - -struct F { - int x; - MyLargeInteger y; -}; - -struct G { - char x; - MyLargeInteger y; - int z; -}; - -struct Array2 { - G t[3]; -}; - -union Union1 { - int intVal[2]; - char ch[8]; - MyLargeInteger my; - short ss[4]; - long long u; -}; - -struct H { - char x[3]; -}; - -struct Union2 { - H x[5]; -}; - -struct J { - short x; - char y[3]; -}; - -union Union3 { - J x[5]; - char y[13]; -}; - -#define DUMP(type) \ -do{ \ -typedef struct _AlignType##type { \ - char c; \ - type d; \ -} AlignType##type; \ -printf("@Test\npublic void testAlign%s() {\ntest(new %s(runtime), %d, %d);\n}\n", #type, #type, offsetof(AlignType##type, d), sizeof(type));\ -} while(0) - -int main() { - DUMP(A); - DUMP(B); - DUMP(C); - DUMP(D); - DUMP(E); - DUMP(Array1); - DUMP(MyLargeInteger); - DUMP(F); - DUMP(G); - DUMP(Array2); - DUMP(Union1); - DUMP(H); - DUMP(Union2); - DUMP(J); - DUMP(Union3); -} - -*/ From 8897ee8e7bac6fab9c0ac14342da77757641e462 Mon Sep 17 00:00:00 2001 From: zhanhb Date: Wed, 25 Oct 2017 00:44:38 +0800 Subject: [PATCH 4/4] Copy source from Struct to StructLayout --- src/main/java/jnr/ffi/StructLayout.java | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/main/java/jnr/ffi/StructLayout.java b/src/main/java/jnr/ffi/StructLayout.java index a1b32cf0b..4a9a5c7ca 100644 --- a/src/main/java/jnr/ffi/StructLayout.java +++ b/src/main/java/jnr/ffi/StructLayout.java @@ -32,7 +32,7 @@ public class StructLayout extends Type { private final Runtime runtime; private final boolean isUnion = false; - private boolean resetIndex = false; + private int currentSize = -1; // only used when this is an enum and add array elements StructLayout enclosing = null; int offset = 0; int size = 0; @@ -100,9 +100,22 @@ private static int align(int offset, int alignment) { return (offset + alignment - 1) & ~(alignment - 1); } + private int nextOffset(int size, int alignment) { + if (isUnion) { + if (currentSize > -1) { // add element to an array + int result = align(this.currentSize, alignment); + this.currentSize = result + size; + return result; + } else { + return 0; + } + } else { + return align(this.size, alignment); + } + } protected final int addField(int size, int align) { - final int off = resetIndex ? 0 : align(this.size, align); + final int off = nextOffset(size, align); this.size = Math.max(this.size, off + size); this.alignment = Math.max(this.alignment, align); this.paddedSize = align(this.size, this.alignment); @@ -162,14 +175,14 @@ public final long offset() { * Starts an array construction session */ protected final void arrayBegin() { - resetIndex = false; + this.currentSize = 0; } /** * Ends an array construction session */ protected final void arrayEnd() { - resetIndex = isUnion; + this.currentSize = -1; } /** @@ -201,7 +214,7 @@ protected final T inner(T structLayout) { structLayout.offset = align(this.size, structLayout.alignment); this.size = structLayout.offset + structLayout.size; this.paddedSize = align(this.size, this.alignment()); - + this.alignment = Math.max(this.alignment, structLayout.alignment); return structLayout; }