Skip to content

Commit 82dc1d6

Browse files
SONARJAVA-5772 Switch from testing object sizes to counting instance fields (#5305)
1 parent 839559d commit 82dc1d6

File tree

2 files changed

+57
-64
lines changed

2 files changed

+57
-64
lines changed

java-frontend/pom.xml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -112,12 +112,6 @@
112112
<groupId>org.sonarsource.analyzer-commons</groupId>
113113
<artifactId>sonar-performance-measure</artifactId>
114114
</dependency>
115-
<dependency>
116-
<groupId>org.openjdk.jol</groupId>
117-
<artifactId>jol-core</artifactId>
118-
<version>0.16</version>
119-
<scope>test</scope>
120-
</dependency>
121115
</dependencies>
122116

123117
<build>

java-frontend/src/test/java/org/sonar/java/model/ClassesLayoutTest.java

Lines changed: 57 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -17,118 +17,117 @@
1717
package org.sonar.java.model;
1818

1919
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;
2520
import org.sonar.java.model.declaration.VariableTreeImpl;
2621
import org.sonar.java.model.expression.IdentifierTreeImpl;
2722
import org.sonar.java.model.expression.LiteralTreeImpl;
2823
import org.sonar.java.model.expression.MemberSelectExpressionTreeImpl;
2924
import org.sonar.java.model.expression.MethodInvocationTreeImpl;
3025

26+
import java.lang.reflect.Field;
27+
import java.lang.reflect.Modifier;
28+
import java.util.HashSet;
29+
3130
import static org.assertj.core.api.Assertions.assertThat;
32-
import static org.junit.jupiter.api.Assertions.assertAll;
3331

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+
*/
3439
class ClassesLayoutTest {
3540

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-
4141
@Test
4242
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);
4744
}
4845

4946
@Test
5047
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);
5549
}
5650

5751
@Test
5852
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);
6354
}
6455

6556
@Test
6657
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);
7159
}
7260

7361
@Test
7462
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);
7964
}
8065

8166
@Test
8267
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);
8769
}
8870

8971
@Test
9072
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);
9574
}
9675

9776
@Test
9877
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);
10379
}
10480

10581
@Test
10682
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);
11184
}
11285

11386
@Test
11487
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);
11989
}
12090

12191
@Test
12292
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);
12794
}
12895

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;
132108
}
133109

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+
}
134133
}

0 commit comments

Comments
 (0)