|
17 | 17 | package org.sonar.java.model;
|
18 | 18 |
|
19 | 19 | import org.junit.jupiter.api.Test;
|
20 |
| -import org.openjdk.jol.datamodel.Model64; |
21 |
| -import org.openjdk.jol.datamodel.Model64_COOPS_CCPS; |
22 |
| -import org.openjdk.jol.info.ClassLayout; |
23 |
| -import org.openjdk.jol.layouters.HotSpotLayouter; |
24 |
| -import org.openjdk.jol.layouters.Layouter; |
25 | 20 | import org.sonar.java.model.declaration.VariableTreeImpl;
|
26 | 21 | import org.sonar.java.model.expression.IdentifierTreeImpl;
|
27 | 22 | import org.sonar.java.model.expression.LiteralTreeImpl;
|
28 | 23 | import org.sonar.java.model.expression.MemberSelectExpressionTreeImpl;
|
29 | 24 | import org.sonar.java.model.expression.MethodInvocationTreeImpl;
|
30 | 25 |
|
| 26 | +import java.lang.reflect.Field; |
| 27 | +import java.lang.reflect.Modifier; |
| 28 | +import java.util.HashSet; |
| 29 | + |
31 | 30 | import static org.assertj.core.api.Assertions.assertThat;
|
32 |
| -import static org.junit.jupiter.api.Assertions.assertAll; |
33 | 31 |
|
| 32 | +/** |
| 33 | + * This test warns you if you are changing classes which have a big impact |
| 34 | + * on memory consumption. If the change is intentional, just update the failing tests. |
| 35 | + * |
| 36 | + * <p>We used to test the size in bytes of instance using jol-core, |
| 37 | + * but it was removed due to licensing. |
| 38 | + */ |
34 | 39 | class ClassesLayoutTest {
|
35 | 40 |
|
36 |
| - private static final int JDK_VERSION = 11; |
37 |
| - |
38 |
| - private static final Layouter X86_64 = new HotSpotLayouter(new Model64(), JDK_VERSION); |
39 |
| - private static final Layouter X86_64_COOPS = new HotSpotLayouter(new Model64_COOPS_CCPS(), JDK_VERSION); |
40 |
| - |
41 | 41 | @Test
|
42 | 42 | void token() {
|
43 |
| - assertAll( |
44 |
| - () -> assertThat(instanceSize(InternalSyntaxToken.class, X86_64)).isEqualTo(72), |
45 |
| - () -> assertThat(instanceSize(InternalSyntaxToken.class, X86_64_COOPS)).isEqualTo(40) |
46 |
| - ); |
| 43 | + assertThat(countFields(InternalSyntaxToken.class)).isEqualTo(7); |
47 | 44 | }
|
48 | 45 |
|
49 | 46 | @Test
|
50 | 47 | void identifier() {
|
51 |
| - assertAll( |
52 |
| - () -> assertThat(instanceSize(IdentifierTreeImpl.class, X86_64)).isEqualTo(88), |
53 |
| - () -> assertThat(instanceSize(IdentifierTreeImpl.class, X86_64_COOPS)).isEqualTo(48) |
54 |
| - ); |
| 48 | + assertThat(countFields(IdentifierTreeImpl.class)).isEqualTo(9); |
55 | 49 | }
|
56 | 50 |
|
57 | 51 | @Test
|
58 | 52 | void literal() {
|
59 |
| - assertAll( |
60 |
| - () -> assertThat(instanceSize(LiteralTreeImpl.class, X86_64)).isEqualTo(64), |
61 |
| - () -> assertThat(instanceSize(LiteralTreeImpl.class, X86_64_COOPS)).isEqualTo(40) |
62 |
| - ); |
| 53 | + assertThat(countFields(LiteralTreeImpl.class)).isEqualTo(6); |
63 | 54 | }
|
64 | 55 |
|
65 | 56 | @Test
|
66 | 57 | void variable_declaration() {
|
67 |
| - assertAll( |
68 |
| - () -> assertThat(instanceSize(VariableTreeImpl.class, X86_64)).isEqualTo(96), |
69 |
| - () -> assertThat(instanceSize(VariableTreeImpl.class, X86_64_COOPS)).isEqualTo(56) |
70 |
| - ); |
| 58 | + assertThat(countFields(VariableTreeImpl.class)).isEqualTo(10); |
71 | 59 | }
|
72 | 60 |
|
73 | 61 | @Test
|
74 | 62 | void member_select() {
|
75 |
| - assertAll( |
76 |
| - () -> assertThat(instanceSize(MemberSelectExpressionTreeImpl.class, X86_64)).isEqualTo(80), |
77 |
| - () -> assertThat(instanceSize(MemberSelectExpressionTreeImpl.class, X86_64_COOPS)).isEqualTo(48) |
78 |
| - ); |
| 63 | + assertThat(countFields(MemberSelectExpressionTreeImpl.class)).isEqualTo(8); |
79 | 64 | }
|
80 | 65 |
|
81 | 66 | @Test
|
82 | 67 | void method_invocation() {
|
83 |
| - assertAll( |
84 |
| - () -> assertThat(instanceSize(MethodInvocationTreeImpl.class, X86_64)).isEqualTo(80), |
85 |
| - () -> assertThat(instanceSize(MethodInvocationTreeImpl.class, X86_64_COOPS)).isEqualTo(48) |
86 |
| - ); |
| 68 | + assertThat(countFields(MethodInvocationTreeImpl.class)).isEqualTo(8); |
87 | 69 | }
|
88 | 70 |
|
89 | 71 | @Test
|
90 | 72 | void type() {
|
91 |
| - assertAll( |
92 |
| - () -> assertThat(instanceSize(JType.class, X86_64)).isEqualTo(72), |
93 |
| - () -> assertThat(instanceSize(JType.class, X86_64_COOPS)).isEqualTo(40) |
94 |
| - ); |
| 73 | + assertThat(countFields(JType.class)).isEqualTo(7); |
95 | 74 | }
|
96 | 75 |
|
97 | 76 | @Test
|
98 | 77 | void symbol_type() {
|
99 |
| - assertAll( |
100 |
| - () -> assertThat(instanceSize(JTypeSymbol.class, X86_64)).isEqualTo(104), |
101 |
| - () -> assertThat(instanceSize(JTypeSymbol.class, X86_64_COOPS)).isEqualTo(56) |
102 |
| - ); |
| 78 | + assertThat(countFields(JTypeSymbol.class)).isEqualTo(11); |
103 | 79 | }
|
104 | 80 |
|
105 | 81 | @Test
|
106 | 82 | void symbol_method() {
|
107 |
| - assertAll( |
108 |
| - () -> assertThat(instanceSize(JMethodSymbol.class, X86_64)).isEqualTo(104), |
109 |
| - () -> assertThat(instanceSize(JMethodSymbol.class, X86_64_COOPS)).isEqualTo(56) |
110 |
| - ); |
| 83 | + assertThat(countFields(JMethodSymbol.class)).isEqualTo(11); |
111 | 84 | }
|
112 | 85 |
|
113 | 86 | @Test
|
114 | 87 | void symbol_variable() {
|
115 |
| - assertAll( |
116 |
| - () -> assertThat(instanceSize(JVariableSymbol.class, X86_64)).isEqualTo(72), |
117 |
| - () -> assertThat(instanceSize(JVariableSymbol.class, X86_64_COOPS)).isEqualTo(40) |
118 |
| - ); |
| 88 | + assertThat(countFields(JVariableSymbol.class)).isEqualTo(7); |
119 | 89 | }
|
120 | 90 |
|
121 | 91 | @Test
|
122 | 92 | void annotation() {
|
123 |
| - assertAll( |
124 |
| - () -> assertThat(instanceSize(JSymbolMetadata.JAnnotationInstance.class, X86_64)).isEqualTo(40), |
125 |
| - () -> assertThat(instanceSize(JSymbolMetadata.JAnnotationInstance.class, X86_64_COOPS)).isEqualTo(24) |
126 |
| - ); |
| 93 | + assertThat(countFields(JSymbolMetadata.JAnnotationInstance.class)).isEqualTo(3); |
127 | 94 | }
|
128 | 95 |
|
129 |
| - private static long instanceSize(Class<?> cls, Layouter layouter) { |
130 |
| - ClassLayout classLayout = ClassLayout.parseClass(cls, layouter); |
131 |
| - return classLayout.instanceSize(); |
| 96 | + /** Count number of fields in instances, including inherited fields. */ |
| 97 | + private static int countFields(Class<?> clazz) { |
| 98 | + int count = 0; |
| 99 | + while (clazz != Object.class) { |
| 100 | + for (Field f : clazz.getDeclaredFields()) { |
| 101 | + if (!Modifier.isStatic(f.getModifiers())) { |
| 102 | + count++; |
| 103 | + } |
| 104 | + } |
| 105 | + clazz = clazz.getSuperclass(); |
| 106 | + } |
| 107 | + return count; |
132 | 108 | }
|
133 | 109 |
|
| 110 | + static class C { |
| 111 | + private int x; |
| 112 | + public long y; |
| 113 | + HashSet<Object> hashSet; |
| 114 | + |
| 115 | + C(int x) { |
| 116 | + this.x = x; |
| 117 | + } |
| 118 | + } |
| 119 | + |
| 120 | + static class D extends C { |
| 121 | + char z; |
| 122 | + static String staticField; |
| 123 | + |
| 124 | + D(int x) { |
| 125 | + super(x); |
| 126 | + } |
| 127 | + } |
| 128 | + |
| 129 | + @Test |
| 130 | + void validateCountFields() { |
| 131 | + assertThat(countFields(D.class)).isEqualTo(4); |
| 132 | + } |
134 | 133 | }
|
0 commit comments