-
Bug
-
Resolution: Fixed
-
P2
-
6.0, 7, 8, 9, 10, 11
There is a discrepancy between the behaviour of Java 9 and the jvmti
spec (http://cr.openjdk.java.net/~mr/jigsaw/spec/jvmti.html#RedefineClasses)
The spec states:
"The redefinition may change method bodies, the constant pool and attributes.
The redefinition must not add, remove or rename fields or methods, change the signatures of methods, change modifiers, or change inheritance."
However, RI allows private methods and inner classes to be added without throwing
JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED.
There is the transform method:
@Override
public byte[] transform(Module module, ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
if (className.equals("p/C")) {
transformModule(module);
byte[] retransformedClazz1Bytes = new LocalDirClassLoader("Instrumentation.redefine_after", null).loadClassData("p/C.class");
} else {
return null;
}
}
that substitutes the class p/C
----------------------------------------------------------------
package p;
public class C {
public static boolean checkReads() {
return false;
}
public static boolean checkUses() {
return false;
}
public static boolean checkProvides() {
return false;
}
}
----------------------------------------------------------------
with the class p/C
----------------------------------------------------------------
package p;
import p3.E;
import java.util.ServiceLoader;
public class C {
public static boolean checkReads() {
return E.getOne() == 1;
}
public static boolean checkUses() {
return ServiceLoader.load(C.class.getModule().getLayer(), ServiceOne.class)
.findFirst()
.map(s -> s instanceof ServiceOneImpl)
.orElse(false);
}
public static boolean checkProvides() {
return ServiceLoader.load(C.class.getModule().getLayer(), ServiceTwo.class)
.findFirst()
.map(s -> s instanceof ServiceTwoImpl)
.orElse(false);
}
}
----------------------------------------------------------------
This retransformation is allowed by RI, although it contradicts the specification above because the transformed class contains extra public static final InnerClass Lookup and methods:
private static synthetic Method lambda$checkProvides$1:"(Lp/ServiceTwo;)Ljava/lang/Boolean;"
private static synthetic Method lambda$checkUses$0:"(Lp/ServiceOne;)Ljava/lang/Boolean;"
The specification should be weakened according to accessibility of methods and/or fields(?).
spec (http://cr.openjdk.java.net/~mr/jigsaw/spec/jvmti.html#RedefineClasses)
The spec states:
"The redefinition may change method bodies, the constant pool and attributes.
The redefinition must not add, remove or rename fields or methods, change the signatures of methods, change modifiers, or change inheritance."
However, RI allows private methods and inner classes to be added without throwing
JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED.
There is the transform method:
@Override
public byte[] transform(Module module, ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
if (className.equals("p/C")) {
transformModule(module);
byte[] retransformedClazz1Bytes = new LocalDirClassLoader("Instrumentation.redefine_after", null).loadClassData("p/C.class");
} else {
return null;
}
}
that substitutes the class p/C
----------------------------------------------------------------
package p;
public class C {
public static boolean checkReads() {
return false;
}
public static boolean checkUses() {
return false;
}
public static boolean checkProvides() {
return false;
}
}
----------------------------------------------------------------
with the class p/C
----------------------------------------------------------------
package p;
import p3.E;
import java.util.ServiceLoader;
public class C {
public static boolean checkReads() {
return E.getOne() == 1;
}
public static boolean checkUses() {
return ServiceLoader.load(C.class.getModule().getLayer(), ServiceOne.class)
.findFirst()
.map(s -> s instanceof ServiceOneImpl)
.orElse(false);
}
public static boolean checkProvides() {
return ServiceLoader.load(C.class.getModule().getLayer(), ServiceTwo.class)
.findFirst()
.map(s -> s instanceof ServiceTwoImpl)
.orElse(false);
}
}
----------------------------------------------------------------
This retransformation is allowed by RI, although it contradicts the specification above because the transformed class contains extra public static final InnerClass Lookup and methods:
private static synthetic Method lambda$checkProvides$1:"(Lp/ServiceTwo;)Ljava/lang/Boolean;"
private static synthetic Method lambda$checkUses$0:"(Lp/ServiceOne;)Ljava/lang/Boolean;"
The specification should be weakened according to accessibility of methods and/or fields(?).
- csr for
-
JDK-8221528 Introduce compatibility mode with VM option -XX:AllowRedefinitionToAddOrDeleteMethods
- Closed
- relates to
-
JDK-6404550 Cannot implement late attach in NetBeans Profiler due to missing functionality in JVMTI
- Resolved
-
JDK-8222934 mark new VM option AllowRedefinitionToAddOrDeleteMethods as deprecated
- Resolved
-
JDK-8181171 Deleting method for RedefineClasses breaks ResolvedMethodName
- Resolved
-
JDK-8024368 private methods are allocated vtable indices
- Resolved