Skip to content

Commit 37c0fd6

Browse files
committed
8296967: [JVMCI] rationalize relationship between getCodeSize and getCode in ResolvedJavaMethod
Reviewed-by: adinn Backport-of: 37848a9ca2ab3021e7b3b2e112bab4631fbe1d99
1 parent 76f0456 commit 37c0fd6

File tree

2 files changed

+208
-51
lines changed

2 files changed

+208
-51
lines changed
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/*
2+
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
package jdk.vm.ci.hotspot.test;
24+
25+
import static java.lang.reflect.Modifier.FINAL;
26+
import static java.lang.reflect.Modifier.PRIVATE;
27+
import static java.lang.reflect.Modifier.PROTECTED;
28+
import static java.lang.reflect.Modifier.PUBLIC;
29+
import static java.lang.reflect.Modifier.STATIC;
30+
import static java.lang.reflect.Modifier.TRANSIENT;
31+
import static java.lang.reflect.Modifier.VOLATILE;
32+
33+
import java.lang.reflect.Field;
34+
import java.lang.reflect.InvocationTargetException;
35+
import java.lang.reflect.Method;
36+
37+
import org.junit.Assert;
38+
import org.junit.Test;
39+
40+
import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
41+
import jdk.vm.ci.hotspot.HotSpotResolvedJavaField;
42+
import jdk.vm.ci.hotspot.HotSpotVMConfigAccess;
43+
import jdk.vm.ci.meta.JavaType;
44+
import jdk.vm.ci.meta.MetaAccessProvider;
45+
import jdk.vm.ci.meta.ResolvedJavaField;
46+
import jdk.vm.ci.meta.ResolvedJavaType;
47+
import jdk.vm.ci.runtime.JVMCI;
48+
49+
/**
50+
* Tests {@link HotSpotResolvedJavaField} functionality.
51+
*/
52+
public class HotSpotResolvedJavaFieldTest {
53+
54+
private static final Class<?>[] classesWithInternalFields = {Class.class, ClassLoader.class};
55+
56+
private static final Method createFieldMethod;
57+
private static final Field indexField;
58+
59+
static {
60+
Method m = null;
61+
Field f = null;
62+
try {
63+
Class<?> typeImpl = Class.forName("jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl");
64+
m = typeImpl.getDeclaredMethod("createField", JavaType.class, long.class, int.class, int.class);
65+
m.setAccessible(true);
66+
Class<?> fieldImpl = Class.forName("jdk.vm.ci.hotspot.HotSpotResolvedJavaFieldImpl");
67+
f = fieldImpl.getDeclaredField("index");
68+
f.setAccessible(true);
69+
} catch (Exception e) {
70+
throw new AssertionError(e);
71+
}
72+
73+
createFieldMethod = m;
74+
indexField = f;
75+
}
76+
77+
/**
78+
* Same as {@code HotSpotModifiers.jvmFieldModifiers()} but works when using a JVMCI version
79+
* prior to the introduction of that method.
80+
*/
81+
private int jvmFieldModifiers() {
82+
HotSpotJVMCIRuntime runtime = runtime();
83+
HotSpotVMConfigAccess access = new HotSpotVMConfigAccess(runtime.getConfigStore());
84+
int accEnum = access.getConstant("JVM_ACC_ENUM", Integer.class, 0x4000);
85+
int accSynthetic = access.getConstant("JVM_ACC_SYNTHETIC", Integer.class, 0x1000);
86+
return PUBLIC | PRIVATE | PROTECTED | STATIC | FINAL | VOLATILE | TRANSIENT | accEnum | accSynthetic;
87+
}
88+
89+
HotSpotJVMCIRuntime runtime() {
90+
return (HotSpotJVMCIRuntime) JVMCI.getRuntime();
91+
}
92+
93+
MetaAccessProvider getMetaAccess() {
94+
return runtime().getHostJVMCIBackend().getMetaAccess();
95+
}
96+
97+
/**
98+
* Tests that {@link HotSpotResolvedJavaField#getModifiers()} only includes the modifiers
99+
* returned by {@link Field#getModifiers()}. Namely, it must not include
100+
* {@code HotSpotResolvedJavaField#FIELD_INTERNAL_FLAG}.
101+
*/
102+
@Test
103+
public void testModifiersForInternal() {
104+
for (Class<?> c : classesWithInternalFields) {
105+
ResolvedJavaType type = getMetaAccess().lookupJavaType(c);
106+
for (ResolvedJavaField field : type.getInstanceFields(false)) {
107+
if (field.isInternal()) {
108+
Assert.assertEquals(0, ~jvmFieldModifiers() & field.getModifiers());
109+
}
110+
}
111+
}
112+
}
113+
114+
/**
115+
* Tests that {@code HotSpotResolvedObjectTypeImpl#createField(String, JavaType, long, int)}
116+
* always returns an {@linkplain ResolvedJavaField#equals(Object) equivalent} object for an
117+
* internal field.
118+
*
119+
* @throws InvocationTargetException
120+
* @throws IllegalArgumentException
121+
* @throws IllegalAccessException
122+
*/
123+
@Test
124+
public void testEquivalenceForInternalFields() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
125+
for (Class<?> c : classesWithInternalFields) {
126+
ResolvedJavaType type = getMetaAccess().lookupJavaType(c);
127+
for (ResolvedJavaField field : type.getInstanceFields(false)) {
128+
if (field.isInternal()) {
129+
HotSpotResolvedJavaField expected = (HotSpotResolvedJavaField) field;
130+
int index = indexField.getInt(expected);
131+
ResolvedJavaField actual = (ResolvedJavaField) createFieldMethod.invoke(type, expected.getType(), expected.getOffset(), expected.getModifiers(), index);
132+
Assert.assertEquals(expected, actual);
133+
}
134+
}
135+
}
136+
}
137+
138+
@Test
139+
public void testIsInObject() {
140+
for (Field f : String.class.getDeclaredFields()) {
141+
HotSpotResolvedJavaField rf = (HotSpotResolvedJavaField) getMetaAccess().lookupJavaField(f);
142+
Assert.assertEquals(rf.toString(), rf.isInObject(runtime().getHostJVMCIBackend().getConstantReflection().forString("a string")), !rf.isStatic());
143+
}
144+
}
145+
}

test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java

Lines changed: 63 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -46,13 +46,16 @@
4646
import java.lang.annotation.RetentionPolicy;
4747
import java.lang.annotation.Target;
4848
import java.lang.reflect.Constructor;
49+
import java.lang.reflect.Executable;
4950
import java.lang.reflect.Member;
5051
import java.lang.reflect.Method;
5152
import java.lang.reflect.Modifier;
5253
import java.lang.reflect.Type;
54+
import java.util.ArrayList;
5355
import java.util.Arrays;
5456
import java.util.HashMap;
5557
import java.util.HashSet;
58+
import java.util.List;
5659
import java.util.Map;
5760
import java.util.Set;
5861

@@ -78,17 +81,13 @@ public TestResolvedJavaMethod() {
7881
*/
7982
@Test
8083
public void getCodeTest() {
81-
for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) {
82-
ResolvedJavaMethod m = e.getValue();
84+
for (ResolvedJavaMethod m : joinValues(methods, constructors)) {
85+
String ms = m.toString();
8386
byte[] code = m.getCode();
8487
if (code == null) {
85-
assertTrue(m.getCodeSize() == 0);
88+
assertEquals(ms, m.getCodeSize(), 0);
8689
} else {
87-
if (m.isAbstract()) {
88-
assertTrue(code.length == 0);
89-
} else if (!m.isNative()) {
90-
assertTrue(code.length > 0);
91-
}
90+
assertTrue(ms, code.length > 0);
9291
}
9392
}
9493
}
@@ -98,26 +97,25 @@ public void getCodeTest() {
9897
*/
9998
@Test
10099
public void getCodeSizeTest() {
101-
for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) {
102-
ResolvedJavaMethod m = e.getValue();
100+
ResolvedJavaType unlinkedType = metaAccess.lookupJavaType(UnlinkedType.class);
101+
assertTrue(!unlinkedType.isLinked());
102+
for (ResolvedJavaMethod m : addExecutables(joinValues(methods, constructors), unlinkedType, false)) {
103103
int codeSize = m.getCodeSize();
104-
if (m.isAbstract()) {
105-
assertTrue(codeSize == 0);
106-
} else if (!m.isNative()) {
107-
assertTrue(codeSize > 0);
104+
String ms = m.toString();
105+
if (m.isAbstract() || m.isNative()) {
106+
assertEquals(ms, codeSize, 0);
107+
} else if (!m.getDeclaringClass().isLinked()) {
108+
assertEquals(ms, -1, codeSize);
109+
} else {
110+
assertTrue(ms, codeSize > 0);
108111
}
109112
}
113+
assertTrue(!unlinkedType.isLinked());
110114
}
111115

112116
@Test
113117
public void getModifiersTest() {
114-
for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) {
115-
ResolvedJavaMethod m = e.getValue();
116-
int expected = e.getKey().getModifiers();
117-
int actual = m.getModifiers();
118-
assertEquals(String.format("%s: 0x%x != 0x%x", m, expected, actual), expected, actual);
119-
}
120-
for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) {
118+
for (Map.Entry<Executable, ResolvedJavaMethod> e : join(methods, constructors).entrySet()) {
121119
ResolvedJavaMethod m = e.getValue();
122120
int expected = e.getKey().getModifiers();
123121
int actual = m.getModifiers();
@@ -130,15 +128,11 @@ public void getModifiersTest() {
130128
*/
131129
@Test
132130
public void isClassInitializerTest() {
133-
for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) {
131+
for (Map.Entry<Executable, ResolvedJavaMethod> e : join(methods, constructors).entrySet()) {
134132
// Class initializers are hidden from reflection
135133
ResolvedJavaMethod m = e.getValue();
136134
assertFalse(m.isClassInitializer());
137135
}
138-
for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) {
139-
ResolvedJavaMethod m = e.getValue();
140-
assertFalse(m.isClassInitializer());
141-
}
142136
}
143137

144138
@Test
@@ -155,11 +149,7 @@ public void isConstructorTest() {
155149

156150
@Test
157151
public void isSyntheticTest() {
158-
for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) {
159-
ResolvedJavaMethod m = e.getValue();
160-
assertEquals(e.getKey().isSynthetic(), m.isSynthetic());
161-
}
162-
for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) {
152+
for (Map.Entry<Executable, ResolvedJavaMethod> e : join(methods, constructors).entrySet()) {
163153
ResolvedJavaMethod m = e.getValue();
164154
assertEquals(e.getKey().isSynthetic(), m.isSynthetic());
165155
}
@@ -179,23 +169,15 @@ public void isBridgeTest() {
179169

180170
@Test
181171
public void isVarArgsTest() {
182-
for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) {
183-
ResolvedJavaMethod m = e.getValue();
184-
assertEquals(e.getKey().isVarArgs(), m.isVarArgs());
185-
}
186-
for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) {
172+
for (Map.Entry<Executable, ResolvedJavaMethod> e : join(methods, constructors).entrySet()) {
187173
ResolvedJavaMethod m = e.getValue();
188174
assertEquals(e.getKey().isVarArgs(), m.isVarArgs());
189175
}
190176
}
191177

192178
@Test
193179
public void isSynchronizedTest() {
194-
for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) {
195-
ResolvedJavaMethod m = e.getValue();
196-
assertEquals(Modifier.isSynchronized(e.getKey().getModifiers()), m.isSynchronized());
197-
}
198-
for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) {
180+
for (Map.Entry<Executable, ResolvedJavaMethod> e : join(methods, constructors).entrySet()) {
199181
ResolvedJavaMethod m = e.getValue();
200182
assertEquals(Modifier.isSynchronized(e.getKey().getModifiers()), m.isSynchronized());
201183
}
@@ -262,7 +244,7 @@ public void asStackTraceElementTest() throws NoSuchMethodException {
262244

263245
@Test
264246
public void getConstantPoolTest() {
265-
for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) {
247+
for (Map.Entry<Executable, ResolvedJavaMethod> e : join(methods, constructors).entrySet()) {
266248
ResolvedJavaMethod m = e.getValue();
267249
ConstantPool cp = m.getConstantPool();
268250
assertTrue(cp.length() > 0);
@@ -399,16 +381,22 @@ public void hasReceiverTest() {
399381
}
400382
}
401383

384+
public static List<ResolvedJavaMethod> addExecutables(List<ResolvedJavaMethod> to, ResolvedJavaType declaringType, boolean forceLink) {
385+
to.addAll(List.of(declaringType.getDeclaredMethods(forceLink)));
386+
to.addAll(List.of(declaringType.getDeclaredConstructors(forceLink)));
387+
return to;
388+
}
389+
402390
@Test
403391
public void hasBytecodesTest() {
404-
for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) {
405-
ResolvedJavaMethod m = e.getValue();
406-
assertTrue(m.hasBytecodes() == (m.isConcrete() && !m.isNative()));
407-
}
408-
for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) {
409-
ResolvedJavaMethod m = e.getValue();
410-
assertTrue(m.hasBytecodes());
392+
ResolvedJavaType unlinkedType = metaAccess.lookupJavaType(UnlinkedType.class);
393+
assertTrue(!unlinkedType.isLinked());
394+
for (ResolvedJavaMethod m : addExecutables(joinValues(methods, constructors), unlinkedType, false)) {
395+
boolean expect = m.getDeclaringClass().isLinked() && m.isConcrete() && !m.isNative();
396+
boolean actual = m.hasBytecodes();
397+
assertEquals(m.toString(), expect, actual);
411398
}
399+
assertTrue(!unlinkedType.isLinked());
412400
}
413401

414402
@Test
@@ -430,7 +418,13 @@ public void isJavaLangObjectInitTest() throws NoSuchMethodException {
430418
}
431419
}
432420

433-
static class UnlinkedType {
421+
abstract static class UnlinkedType {
422+
abstract void abstractMethod();
423+
424+
void concreteMethod() {
425+
}
426+
427+
native void nativeMethod();
434428
}
435429

436430
/**
@@ -513,4 +507,22 @@ public void testCoverage() {
513507
}
514508
}
515509
}
510+
511+
@SafeVarargs
512+
public static <K, V> Map<K, V> join(Map<? extends K, V>... maps) {
513+
Map<K, V> res = new HashMap<>();
514+
for (Map<? extends K, V> e : maps) {
515+
res.putAll(e);
516+
}
517+
return res;
518+
}
519+
520+
@SafeVarargs
521+
public static <V> List<V> joinValues(Map<?, V>... maps) {
522+
List<V> res = new ArrayList<>();
523+
for (Map<?, V> e : maps) {
524+
res.addAll(e.values());
525+
}
526+
return res;
527+
}
516528
}

0 commit comments

Comments
 (0)