Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
Expand Down Expand Up @@ -103,6 +104,17 @@ HotSpotResolvedObjectType getEnclosingClass(HotSpotResolvedObjectTypeImpl holder
return (HotSpotResolvedObjectType) runtime().fromClass(javaMirror.getEnclosingClass());
}

@Override
HotSpotResolvedJavaMethod getEnclosingMethod(HotSpotResolvedObjectTypeImpl holder) {
Class<?> javaMirror = getMirror(holder);
Method enclosingMethod = javaMirror.getEnclosingMethod();
Executable enclosingExecutable = enclosingMethod != null ? enclosingMethod : javaMirror.getEnclosingConstructor();
if (enclosingExecutable == null) {
return null;
}
return compilerToVM().asResolvedJavaMethod(enclosingExecutable);
}

@Override
boolean equals(HotSpotObjectConstantImpl a, HotSpotObjectConstantImpl b) {
return resolveObject(a) == resolveObject(b) && a.isCompressed() == b.isCompressed();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ abstract class HotSpotJVMCIReflection {

abstract HotSpotResolvedObjectType getEnclosingClass(HotSpotResolvedObjectTypeImpl holder);

abstract HotSpotResolvedJavaMethod getEnclosingMethod(HotSpotResolvedObjectTypeImpl holder);

abstract boolean equals(HotSpotObjectConstantImpl hotSpotResolvedJavaType, HotSpotObjectConstantImpl that);

abstract ResolvedJavaMethod.Parameter[] getParameters(HotSpotResolvedJavaMethodImpl javaMethod);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ public HotSpotResolvedObjectType getArrayClass() {
return arrayOfType;
}

@Override
public abstract HotSpotResolvedJavaMethod getEnclosingMethod();

/**
* Checks whether this type is currently being initialized. If a type is being initialized it
* implies that it was {@link #isLinked() linked} and that the static initializer is currently
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1145,6 +1145,11 @@ public HotSpotResolvedObjectType getEnclosingType() {
return runtime().reflection.getEnclosingClass(this);
}

@Override
public HotSpotResolvedJavaMethod getEnclosingMethod() {
return runtime().reflection.getEnclosingMethod(this);
}

@Override
public ResolvedJavaMethod[] getDeclaredConstructors() {
link();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,11 @@ public ResolvedJavaType getEnclosingType() {
return null;
}

@Override
public HotSpotResolvedJavaMethod getEnclosingMethod() {
return null;
}

@Override
public ResolvedJavaMethod[] getDeclaredConstructors() {
return new ResolvedJavaMethod[0];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ HotSpotResolvedObjectType getEnclosingClass(HotSpotResolvedObjectTypeImpl holder
throw new HotSpotJVMCIUnsupportedOperationError("requires a call Class.getEnclosingClass()");
}

@Override
HotSpotResolvedJavaMethod getEnclosingMethod(HotSpotResolvedObjectTypeImpl holder) {
throw new HotSpotJVMCIUnsupportedOperationError("requires a call Class.getEnclosingMethod()");
}

@Override
boolean equals(HotSpotObjectConstantImpl x, HotSpotObjectConstantImpl y) {
if (x == y) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,26 @@ default ResolvedJavaMethod resolveConcreteMethod(ResolvedJavaMethod method, Reso
*/
ResolvedJavaType getEnclosingType();

/**
* Returns a {@link ResolvedJavaMethod} representing the immediately enclosing
* method or constructor of the underlying type, if this type represents a local
* or anonymous class within a method. Returns {@code null} otherwise.
*
* In particular, this method returns {@code null} if the underlying
* type is a local or anonymous class immediately enclosed by a class or
* interface declaration, instance initializer or static initializer.
*
* Note that in contrast to {@link Class#getEnclosingMethod()}, this returns
* both, methods and constructors.
*
* @return the immediately enclosing method or constructor of the underlying
* class, if this type is a local or anonymous class, otherwise {@code null}.
*
* @see Class#getEnclosingMethod()
* @see Class#getEnclosingConstructor()
*/
ResolvedJavaMethod getEnclosingMethod();

/**
* Returns an array reflecting all the constructors declared by this type. This method is
* similar to {@link Class#getDeclaredConstructors()} in terms of returned constructors. Calling
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
Expand Down Expand Up @@ -767,6 +768,57 @@ private void assertGetPermittedSubclasses(Class<?> clazz) {
}
}

@Test
public void getEnclosingMethodTest() {
// no anonymous class -> expected null
Object obj0 = new Object();
testEnclosingMethod(obj0.getClass(), false);

// anonymous class -> not null
Object obj1 = new Object() {};
testEnclosingMethod(obj1.getClass(), true);

// local class -> not null
class Foo {};
testEnclosingMethod(Foo.class, true);

class Bar {
final Object obj0;
final Object obj1;
final Object obj2;

Bar() {
// no anonymous class -> expected null
obj0 = new Object();

// anonymous class -> not null
obj1 = new Object() {};

// local class -> not null
class Foo {};
obj2 = new Foo();
}
}
Bar bar = new Bar();
testEnclosingMethod(bar.obj0.getClass(), false);
testEnclosingMethod(bar.obj1.getClass(), true);
testEnclosingMethod(bar.obj2.getClass(), true);
}

private static void testEnclosingMethod(Class<?> clazz, boolean isEnclosed) {
ResolvedJavaType type = metaAccess.lookupJavaType(clazz);
Method enclosingMethod = clazz.getEnclosingMethod();
Executable expected = enclosingMethod != null ? enclosingMethod : clazz.getEnclosingConstructor();
ResolvedJavaMethod actual = type.getEnclosingMethod();
if (expected == null) {
assertFalse(isEnclosed);
assertNull(actual);
} else {
assertTrue(isEnclosed);
assertEquals(metaAccess.lookupJavaMethod(expected), actual);
}
}

static final Map<Class<?>, VTable> vtables = new HashMap<>();

static class VTable {
Expand Down
Loading