@@ -8,6 +8,15 @@ The purpose of the project is to maintain enhanced class redefinition functional | |||
You can download binaries [here](https://dcevm.github.io/). | |||
## Dcevm for Java9 and Java10 | |||
Dcevm8 is last version supported by this project. New versions are moved to separated projects extended from OpenJDK under HotswapProjects umbrella. | |||
* [Dcevm9](https://github.com/HotswapProjects/openjdk-jdk9) | |||
* [Dcevm10](https://github.com/HotswapProjects/openjdk-jdk10) | |||
Dcevm patch is hosted in dedicated **dcevm** branch in each repository. | |||
## Supported versions | |||
[hotspot/.hg/patches/](hotspot/.hg/patches/) contains patches for all supported versions. Each patch is named by concatenating prefix `full` or `light` with the OpenJDK HotSpot tag. `full` patches support full redefenition capabilities (including removal of superclasses, for example). `light` patches are easier to maintain, but they only support limited functionality (generally, additions to class hierarchies are fine, removals are not). |
@@ -26,6 +26,7 @@ package com.github.dcevm.test; | |||
import com.github.dcevm.HotSwapTool; | |||
import org.junit.Assert; | |||
import java.lang.reflect.Field; | |||
/** | |||
* Utility methods for unit testing. | |||
@@ -71,4 +72,17 @@ public class TestUtil { | |||
}); | |||
} | |||
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); | |||
} | |||
} | |||
} |
@@ -0,0 +1,86 @@ | |||
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)); | |||
} | |||
} |
@@ -0,0 +1,111 @@ | |||
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)); | |||
} | |||
} |
@@ -0,0 +1,28 @@ | |||
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)); | |||
} | |||
@@ -54,5 +54,6 @@ light-jdk8u152-b16.patch #+light-jdk8u152-b16 #+light-jdk8u161-b12 #+light-jdk8u | |||
jvmti-getLoadedClasses-java8.patch #+light-jdk8u112-b16 #+light-jdk8u144-b01 #+light-jdk8u152-b16 #+light-jdk8u161-b12 #+light-jdk8u162-b12 | |||
jvmti-lockRedefine-java8.patch #+light-jdk8u144-b01delete | |||
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-jdk8u161-b12 #+light-jdk8u162-b12 | |||
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-jdk8u161-b12 #+light-jdk8u162-b12 | |||
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 | |||
light-updateClassRedefinedCount-java8.patch #+light-jdk8u112-b16 #+light-jdk8u144-b01 #+light-jdk8u152-b16 |