Skip to content

Commit ec0d856

Browse files
committed
[JVMCI] Add ResolvedJavaType#getEnclosingMethod [GR-70132]
1 parent a55dff5 commit ec0d856

File tree

8 files changed

+121
-0
lines changed

8 files changed

+121
-0
lines changed

src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJDKReflection.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
import java.lang.annotation.Annotation;
2929
import java.lang.reflect.Array;
30+
import java.lang.reflect.Constructor;
3031
import java.lang.reflect.Executable;
3132
import java.lang.reflect.Field;
3233
import java.lang.reflect.Method;
@@ -103,6 +104,26 @@ HotSpotResolvedObjectType getEnclosingClass(HotSpotResolvedObjectTypeImpl holder
103104
return (HotSpotResolvedObjectType) runtime().fromClass(javaMirror.getEnclosingClass());
104105
}
105106

107+
@Override
108+
HotSpotResolvedJavaMethod getEnclosingMethod(HotSpotResolvedObjectTypeImpl holder) {
109+
Class<?> javaMirror = getMirror(holder);
110+
Method enclosingMethod = javaMirror.getEnclosingMethod();
111+
if (enclosingMethod == null) {
112+
return null;
113+
}
114+
return compilerToVM().asResolvedJavaMethod(enclosingMethod);
115+
}
116+
117+
@Override
118+
HotSpotResolvedJavaMethod getEnclosingConstructor(HotSpotResolvedObjectTypeImpl holder) {
119+
Class<?> javaMirror = getMirror(holder);
120+
Constructor<?> enclosingMethod = javaMirror.getEnclosingConstructor();
121+
if (enclosingMethod == null) {
122+
return null;
123+
}
124+
return compilerToVM().asResolvedJavaMethod(enclosingMethod);
125+
}
126+
106127
@Override
107128
boolean equals(HotSpotObjectConstantImpl a, HotSpotObjectConstantImpl b) {
108129
return resolveObject(a) == resolveObject(b) && a.isCompressed() == b.isCompressed();

src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIReflection.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ abstract class HotSpotJVMCIReflection {
5050

5151
abstract HotSpotResolvedObjectType getEnclosingClass(HotSpotResolvedObjectTypeImpl holder);
5252

53+
abstract HotSpotResolvedJavaMethod getEnclosingMethod(HotSpotResolvedObjectTypeImpl holder);
54+
55+
abstract HotSpotResolvedJavaMethod getEnclosingConstructor(HotSpotResolvedObjectTypeImpl holder);
56+
5357
abstract boolean equals(HotSpotObjectConstantImpl hotSpotResolvedJavaType, HotSpotObjectConstantImpl that);
5458

5559
abstract ResolvedJavaMethod.Parameter[] getParameters(HotSpotResolvedJavaMethodImpl javaMethod);

src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ public HotSpotResolvedObjectType getArrayClass() {
6161
return arrayOfType;
6262
}
6363

64+
@Override
65+
public abstract HotSpotResolvedJavaMethod getEnclosingMethod();
66+
6467
/**
6568
* Checks whether this type is currently being initialized. If a type is being initialized it
6669
* implies that it was {@link #isLinked() linked} and that the static initializer is currently

src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,6 +1145,12 @@ public HotSpotResolvedObjectType getEnclosingType() {
11451145
return runtime().reflection.getEnclosingClass(this);
11461146
}
11471147

1148+
@Override
1149+
public HotSpotResolvedJavaMethod getEnclosingMethod() {
1150+
HotSpotResolvedJavaMethod enclosingMethod = runtime().reflection.getEnclosingMethod(this);
1151+
return enclosingMethod != null ? enclosingMethod : runtime().reflection.getEnclosingConstructor(this);
1152+
}
1153+
11481154
@Override
11491155
public ResolvedJavaMethod[] getDeclaredConstructors() {
11501156
link();

src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,11 @@ public ResolvedJavaType getEnclosingType() {
312312
return null;
313313
}
314314

315+
@Override
316+
public HotSpotResolvedJavaMethod getEnclosingMethod() {
317+
return null;
318+
}
319+
315320
@Override
316321
public ResolvedJavaMethod[] getDeclaredConstructors() {
317322
return new ResolvedJavaMethod[0];

src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/SharedLibraryJVMCIReflection.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,16 @@ HotSpotResolvedObjectType getEnclosingClass(HotSpotResolvedObjectTypeImpl holder
7171
throw new HotSpotJVMCIUnsupportedOperationError("requires a call Class.getEnclosingClass()");
7272
}
7373

74+
@Override
75+
HotSpotResolvedJavaMethod getEnclosingMethod(HotSpotResolvedObjectTypeImpl holder) {
76+
throw new HotSpotJVMCIUnsupportedOperationError("requires a call Class.getEnclosingMethod()");
77+
}
78+
79+
@Override
80+
HotSpotResolvedJavaMethod getEnclosingConstructor(HotSpotResolvedObjectTypeImpl holder) {
81+
throw new HotSpotJVMCIUnsupportedOperationError("requires a call Class.getEnclosingConstructor()");
82+
}
83+
7484
@Override
7585
boolean equals(HotSpotObjectConstantImpl x, HotSpotObjectConstantImpl y) {
7686
if (x == y) {

src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,26 @@ default ResolvedJavaMethod resolveConcreteMethod(ResolvedJavaMethod method, Reso
404404
*/
405405
ResolvedJavaType getEnclosingType();
406406

407+
/**
408+
* Returns a {@link ResolvedJavaMethod} representing the immediately enclosing
409+
* method or constructor of the underlying type, if this type represents a local
410+
* or anonymous class within a method. Returns {@code null} otherwise.
411+
*
412+
* In particular, this method returns {@code null} if the underlying
413+
* type is a local or anonymous class immediately enclosed by a class or
414+
* interface declaration, instance initializer or static initializer.
415+
*
416+
* Note that in contrast to {@link Class#getEnclosingMethod()}, this returns
417+
* both, methods and constructors.
418+
*
419+
* @return the immediately enclosing method or constructor of the underlying
420+
* class, if this type is a local or anonymous class, otherwise {@code null}.
421+
*
422+
* @see Class#getEnclosingMethod()
423+
* @see Class#getEnclosingConstructor()
424+
*/
425+
ResolvedJavaMethod getEnclosingMethod();
426+
407427
/**
408428
* Returns an array reflecting all the constructors declared by this type. This method is
409429
* similar to {@link Class#getDeclaredConstructors()} in terms of returned constructors. Calling

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

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
import java.lang.invoke.MethodHandles.Lookup;
6565
import java.lang.reflect.AccessibleObject;
6666
import java.lang.reflect.Constructor;
67+
import java.lang.reflect.Executable;
6768
import java.lang.reflect.Field;
6869
import java.lang.reflect.Method;
6970
import java.lang.reflect.Modifier;
@@ -767,6 +768,57 @@ private void assertGetPermittedSubclasses(Class<?> clazz) {
767768
}
768769
}
769770

771+
@Test
772+
public void getEnclosingMethodTest() {
773+
// no anonymous class -> expected null
774+
Object obj0 = new Object();
775+
testEnclosingMethod(obj0.getClass(), false);
776+
777+
// anonymous class -> not null
778+
Object obj1 = new Object() {};
779+
testEnclosingMethod(obj1.getClass(), true);
780+
781+
// local class -> not null
782+
class Foo {};
783+
testEnclosingMethod(Foo.class, true);
784+
785+
class Bar {
786+
final Object obj0;
787+
final Object obj1;
788+
final Object obj2;
789+
790+
Bar() {
791+
// no anonymous class -> expected null
792+
obj0 = new Object();
793+
794+
// anonymous class -> not null
795+
obj1 = new Object() {};
796+
797+
// local class -> not null
798+
class Foo {};
799+
obj2 = new Foo();
800+
}
801+
}
802+
Bar bar = new Bar();
803+
testEnclosingMethod(bar.obj0.getClass(), false);
804+
testEnclosingMethod(bar.obj1.getClass(), true);
805+
testEnclosingMethod(bar.obj2.getClass(), true);
806+
}
807+
808+
private static void testEnclosingMethod(Class<?> clazz, boolean isEnclosed) {
809+
ResolvedJavaType type = metaAccess.lookupJavaType(clazz);
810+
Method enclosingMethod = clazz.getEnclosingMethod();
811+
Executable expected = enclosingMethod != null ? enclosingMethod : clazz.getEnclosingConstructor();
812+
ResolvedJavaMethod actual = type.getEnclosingMethod();
813+
if (expected == null) {
814+
assertFalse(isEnclosed);
815+
assertNull(actual);
816+
} else {
817+
assertTrue(isEnclosed);
818+
assertEquals(metaAccess.lookupJavaMethod(expected), actual);
819+
}
820+
}
821+
770822
static final Map<Class<?>, VTable> vtables = new HashMap<>();
771823

772824
static class VTable {

0 commit comments

Comments
 (0)