import com.github.dcevm.HotSwapTool; | import com.github.dcevm.HotSwapTool; | ||||
import org.junit.Assert; | import org.junit.Assert; | ||||
import java.lang.reflect.Field; | |||||
/** | /** | ||||
* Utility methods for unit testing. | * Utility methods for unit testing. | ||||
}); | }); | ||||
} | } | ||||
public static int getClassRedefinedCount(Class type) { | |||||
try { | |||||
Field field = Class.class.getDeclaredField("classRedefinedCount"); | |||||
boolean accessibility = field.isAccessible(); | |||||
field.setAccessible(true); | |||||
int classRedefinedCount = (Integer) field.get(type); | |||||
field.setAccessible(accessibility); | |||||
return classRedefinedCount; | |||||
} catch (Exception e) { | |||||
throw new RuntimeException(e); | |||||
} | |||||
} | |||||
} | } |
package com.github.dcevm.test.fields; | |||||
import com.github.dcevm.HotSwapTool; | |||||
import com.github.dcevm.test.TestUtil; | |||||
import com.github.dcevm.test.category.Light; | |||||
import org.junit.Before; | |||||
import org.junit.Test; | |||||
import org.junit.experimental.categories.Category; | |||||
import static com.github.dcevm.test.util.HotSwapTestHelper.__toVersion__; | |||||
import static org.junit.Assert.assertEquals; | |||||
@Category(Light.class) | |||||
public class FieldOperationsUpdateClassRedefinedCount { | |||||
// Version 0 | |||||
public static class A { | |||||
public int x; | |||||
int getFieldInOldCode() { | |||||
__toVersion__(1); | |||||
// This field does no longer exist | |||||
return x; | |||||
} | |||||
int getVer() { | |||||
return 0; | |||||
} | |||||
} | |||||
// Version 1 | |||||
public static class A___1 { | |||||
public int x; | |||||
public int y; | |||||
int getVer() { | |||||
return 1; | |||||
} | |||||
} | |||||
public static class A___2 { | |||||
int getVer() { | |||||
return 2; | |||||
} | |||||
} | |||||
@Before | |||||
public void setUp() throws Exception { | |||||
__toVersion__(0); | |||||
} | |||||
@Test | |||||
public void addingFieldUpdatesClassRedifinedCount() throws NoSuchFieldException, IllegalAccessException { | |||||
// setup | |||||
A a = new A(); | |||||
__toVersion__(0); | |||||
int prevVersion = TestUtil.getClassRedefinedCount(A.class); | |||||
// examine | |||||
__toVersion__(1); | |||||
Object y = A.class.getDeclaredField("y").get(a); | |||||
// verify | |||||
assertEquals(0,y); | |||||
assertEquals(1, a.getVer()); | |||||
assertEquals(prevVersion+1, TestUtil.getClassRedefinedCount(A.class)); | |||||
} | |||||
@Test | |||||
public void deletingFieldUpdatesClassRedifinedCount() { | |||||
// setup | |||||
A a= new A(); | |||||
__toVersion__(0); | |||||
int prevVersion = TestUtil.getClassRedefinedCount(A.class); | |||||
// examine | |||||
__toVersion__(2); | |||||
// verify | |||||
assertEquals(2, a.getVer()); | |||||
assertEquals(prevVersion+1, TestUtil.getClassRedefinedCount(A.class)); | |||||
} | |||||
} |
package com.github.dcevm.test.methods; | |||||
import com.github.dcevm.test.TestUtil; | |||||
import org.junit.Before; | |||||
import org.junit.Test; | |||||
import static com.github.dcevm.test.util.HotSwapTestHelper.__toVersion__; | |||||
import static org.junit.Assert.assertEquals; | |||||
public class OperationsOnMethodsUpdateClassRedefinedCount { | |||||
// Version 0 | |||||
public static class A { | |||||
public int value(int newVersion) { | |||||
return newVersion; | |||||
} | |||||
} | |||||
// Version 1 | |||||
public static class A___1 { | |||||
public int value(int newVersion) { | |||||
int x = 1; | |||||
try { | |||||
x = 2; | |||||
} catch (NumberFormatException e) { | |||||
x = 3; | |||||
} catch (Exception e) { | |||||
x = 4; | |||||
} finally { | |||||
x = x * 2; | |||||
} | |||||
__toVersion__(newVersion); | |||||
throw new IllegalArgumentException(); | |||||
} | |||||
} | |||||
// Version 2 | |||||
public static class A___2 { | |||||
public int value2() { | |||||
return 2; | |||||
} | |||||
public int value(int newVersion) { | |||||
int x = 1; | |||||
try { | |||||
x = 2; | |||||
} catch (NumberFormatException e) { | |||||
x = 3; | |||||
} catch (Exception e) { | |||||
x = 4; | |||||
} finally { | |||||
x = x * 2; | |||||
} | |||||
__toVersion__(newVersion); | |||||
throw new IllegalArgumentException(); | |||||
} | |||||
public int value3() { | |||||
return 3; | |||||
} | |||||
public int value4() { | |||||
return 4; | |||||
} | |||||
public int value5() { | |||||
return 5; | |||||
} | |||||
} | |||||
@Before | |||||
public void setUp() throws Exception { | |||||
__toVersion__(0); | |||||
} | |||||
@Test | |||||
public void changingMethodUpdatesClassRedefinedCount() { | |||||
// setup | |||||
__toVersion__(0); | |||||
int prevVersion = TestUtil.getClassRedefinedCount(A.class); | |||||
// examine | |||||
__toVersion__(1); | |||||
// verify | |||||
assertEquals(prevVersion+1, TestUtil.getClassRedefinedCount(A.class)); | |||||
} | |||||
@Test | |||||
public void addingMethodUpdatesClassRedefinedCount() { | |||||
// setup | |||||
__toVersion__(0); | |||||
int prevVersion = TestUtil.getClassRedefinedCount(A.class); | |||||
// examine | |||||
__toVersion__(2); | |||||
// verify | |||||
assertEquals(prevVersion+1, TestUtil.getClassRedefinedCount(A.class)); | |||||
} | |||||
@Test | |||||
public void deletingMethodUpdatesClassRedefinedCount() { | |||||
// setup | |||||
__toVersion__(2); | |||||
int prevVersion = TestUtil.getClassRedefinedCount(A.class); | |||||
// examine | |||||
__toVersion__(0); | |||||
// verify | |||||
assertEquals(prevVersion+1, TestUtil.getClassRedefinedCount(A.class)); | |||||
} | |||||
} |
diff -r 7bb5278e8ce7 src/share/vm/prims/jvmtiRedefineClasses2.cpp | |||||
--- a/src/share/vm/prims/jvmtiRedefineClasses2.cpp Fri Mar 23 15:32:54 2018 +0100 | |||||
+++ b/src/share/vm/prims/jvmtiRedefineClasses2.cpp Sat Mar 24 15:49:52 2018 +0100 | |||||
@@ -1763,8 +1763,8 @@ | |||||
// increment the classRedefinedCount field in the_class and in any | |||||
// direct and indirect subclasses of the_class | |||||
- increment_class_counter((InstanceKlass *)the_old_class(), THREAD); | |||||
- | |||||
+ increment_class_counter((InstanceKlass *)the_new_class(), THREAD); | |||||
+ | |||||
} | |||||
@@ -1864,10 +1864,10 @@ | |||||
// Increment the classRedefinedCount field in the specific InstanceKlass | |||||
// and in all direct and indirect subclasses. | |||||
-void VM_EnhancedRedefineClasses::increment_class_counter(Klass* klass, TRAPS) { | |||||
- oop class_mirror = klass->java_mirror(); | |||||
+void VM_EnhancedRedefineClasses::increment_class_counter(Klass* klass, TRAPS) { | |||||
+ oop class_mirror = klass->old_version()->java_mirror(); | |||||
int new_count = java_lang_Class::classRedefinedCount(class_mirror) + 1; | |||||
- java_lang_Class::set_classRedefinedCount(class_mirror, new_count); | |||||
+ java_lang_Class::set_classRedefinedCount(klass->java_mirror(), new_count); | |||||
RC_TRACE(0x00000008, ("updated count for class=%s to %d", klass->external_name(), new_count)); | |||||
} | |||||
light-jdk8u20-deopt-cp.patch #+light-jdk8u20-b22 #+light-jdk8u31-b13 #+light-jdk8u40-b25 #+light-jdk8u45-b14 #+light-jdk8u51-b16 | light-jdk8u20-deopt-cp.patch #+light-jdk8u20-b22 #+light-jdk8u31-b13 #+light-jdk8u40-b25 #+light-jdk8u45-b14 #+light-jdk8u51-b16 | ||||
light-jdk8u66-b17-deopt-cp.patch #+light-jdk8u66-b17 #+light-jdk8u74-b02 #+light-jdk8u92-b14 #+light-jdk8u102-b31 #+light-jdk8u111-b14 #+light-jdk8u112-b16 #+light-jdk8u144-b01 #+light-jdk8u152-b16 | light-jdk8u66-b17-deopt-cp.patch #+light-jdk8u66-b17 #+light-jdk8u74-b02 #+light-jdk8u92-b14 #+light-jdk8u102-b31 #+light-jdk8u111-b14 #+light-jdk8u112-b16 #+light-jdk8u144-b01 #+light-jdk8u152-b16 | ||||
dont-clear-f1.patch #+light-jdk8u74-b02 #+light-jdk8u92-b14 #+light-jdk8u102-b31 #+light-jdk8u111-b14 #+light-jdk8u112-b16 #+light-jdk8u144-b01 #+light-jdk8u152-b16 | dont-clear-f1.patch #+light-jdk8u74-b02 #+light-jdk8u92-b14 #+light-jdk8u102-b31 #+light-jdk8u111-b14 #+light-jdk8u112-b16 #+light-jdk8u144-b01 #+light-jdk8u152-b16 | ||||
light-updateClassRedefinedCount-java8.patch #+light-jdk8u112-b16 #+light-jdk8u144-b01 #+light-jdk8u152-b16 |