diff options
author | Ivan Dubrov <idubrov@guidewire.com> | 2014-04-24 19:22:17 -0700 |
---|---|---|
committer | Ivan Dubrov <idubrov@guidewire.com> | 2014-04-24 19:22:17 -0700 |
commit | 070f0932b7f5f901551d42850b1c105a080cc40b (patch) | |
tree | cfa0d0be6e34ae108180d071b77c98b8994ebb8c /dcevm | |
parent | f3d1c500f2cb30e2203df86844b378ea1b6bc53d (diff) | |
download | dcevm-070f0932b7f5f901551d42850b1c105a080cc40b.tar.gz dcevm-070f0932b7f5f901551d42850b1c105a080cc40b.zip |
Adding Java 7 patch, support running tests on Java 7
Diffstat (limited to 'dcevm')
55 files changed, 6574 insertions, 0 deletions
diff --git a/dcevm/src/main/java/org/dcevm/ClassRedefinitionPolicy.java b/dcevm/src/main/java/org/dcevm/ClassRedefinitionPolicy.java new file mode 100644 index 00000000..32571863 --- /dev/null +++ b/dcevm/src/main/java/org/dcevm/ClassRedefinitionPolicy.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package org.dcevm; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * @author Kerstin Breiteneder + */ +@Retention(value = RetentionPolicy.RUNTIME) +public @interface ClassRedefinitionPolicy { + + // Default value if no alias is set. + public final static class NoClass { + } + + Class<?> alias() default NoClass.class; +} diff --git a/dcevm/src/main/java/org/dcevm/HotSwapTool.java b/dcevm/src/main/java/org/dcevm/HotSwapTool.java new file mode 100644 index 00000000..b622cba9 --- /dev/null +++ b/dcevm/src/main/java/org/dcevm/HotSwapTool.java @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package org.dcevm; + +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Type; + +import java.io.*; +import java.lang.instrument.UnmodifiableClassException; +import java.net.URL; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Map; + +/** + * @author Thomas Wuerthinger + * @author Kerstin Breiteneder + * @author Christoph Wimberger + * @author Ivan Dubrov + */ +public class HotSwapTool { + + /** + * Prefix for the version number in the class name. The class bytes are modified that this string including + * the following number is removed. This means that e.g. A___2 is treated as A anywhere in the source code. This is introduced + * to make the IDE not complain about multiple defined classes. + */ + public static final String IDENTIFIER = "___"; + private static final String CLASS_FILE_SUFFIX = ".class"; + private static Map<Class<?>, Integer> currentVersion = new Hashtable<Class<?>, Integer>(); + private static Redefiner redefiner; + private static int redefinitionCount; + private static long totalTime; + + static { + try { + //redefiner = new JDIRedefiner(4000); + redefiner = new InstrumentationRedefiner(); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + + /** + * Returns the current version of the inner classes of a specified outer class. + * + * @param baseClass the outer class whose version is queried + * @return the version of the inner classes of the specified outer class + */ + public static int getCurrentVersion(Class<?> baseClass) { + if (!currentVersion.containsKey(baseClass)) { + currentVersion.put(baseClass, 0); + } + return currentVersion.get(baseClass); + } + + /** + * Performs an explicit shutdown and disconnects from the VM. + */ + public static void shutdown() throws IOException { + redefiner.close(); + redefiner = null; + } + + private static Map<Class<?>, byte[]> buildRedefinitionMap(Map<String, File> classes) throws IOException, ClassNotFoundException { + // Collect rename rules + // Also, makes sure all classes are loaded in the VM, before they are redefined + final Map<String, String> typeMappings = new HashMap<String, String>(); + for (String name : classes.keySet()) { + Class<?> clazz = Class.forName(name); // FIXME: classloader? + ClassRedefinitionPolicy policy = clazz.getAnnotation(ClassRedefinitionPolicy.class); + Class<?> replacement = (policy != null && policy.alias() != ClassRedefinitionPolicy.NoClass.class) ? + policy.alias() : clazz; + typeMappings.put(Type.getInternalName(clazz), stripVersion(Type.getInternalName(replacement))); + + } + + Map<Class<?>, byte[]> classesMap = new HashMap<Class<?>, byte[]>(); + for (File file : classes.values()) { + loadAdaptedClass(file, typeMappings, classesMap); + } + return classesMap; + } + + private static void loadAdaptedClass(File file, Map<String, String> typeMappnigs, Map<Class<?>, byte[]> result) throws IOException, ClassNotFoundException { + + ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); + TestClassAdapter adapter = new TestClassAdapter(writer, typeMappnigs); + + InputStream in = new FileInputStream(file); + try { + new ClassReader(in).accept(adapter, ClassReader.EXPAND_FRAMES); + } finally { + try { + in.close(); + } catch (IOException e) { + // Ignore. + } + } + byte[] bytes = writer.toByteArray(); + String className = adapter.getClassName().replace('/', '.'); + result.put(Class.forName(className), bytes); // FIXME: ClassLoader... + } + + /** + * Redefines all inner classes of a outer class to a specified version. Inner classes who do not have a particular + * representation for a version remain unchanged. + * + * @param outerClass the outer class whose inner classes should be redefined + * @param versionNumber the target version number + */ + public static void toVersion(Class<?> outerClass, int versionNumber) { + assert versionNumber >= 0; + + if (versionNumber == getCurrentVersion(outerClass)) { + // Nothing to do! + return; + } + + Map<String, File> files = findClassesWithVersion(outerClass, versionNumber); + + try { + Map<Class<?>, byte[]> map = buildRedefinitionMap(files); + + long startTime = System.currentTimeMillis(); + redefiner.redefineClasses(map); + long curTime = System.currentTimeMillis() - startTime; + totalTime += curTime; + redefinitionCount++; + + } catch (UnmodifiableClassException e) { + throw new UnsupportedOperationException(e); + } catch (ClassNotFoundException e) { + throw new RuntimeException("Cannot redefine classes", e); + } catch (IOException e) { + throw new RuntimeException("Cannot redefine classes", e); + } + + setCurrentVersion(outerClass, versionNumber); + } + + private static Map<String, File> findClassesWithVersion(Class<?> baseClass, int version) { + Map<String, File> classes = new HashMap<String, File>(); + + String packageName = baseClass.getPackage().getName().replace('.', '/'); + URL url = baseClass.getClassLoader().getResource(packageName); + if (url == null) { + throw new IllegalArgumentException("Cannot find URL corresponding to the package '" + packageName + "'"); + } + File folder = new File(url.getFile()); + for (File f : folder.listFiles(IsClassFile.INSTANCE)) { + String fileName = f.getName(); + String simpleName = f.getName().substring(0, f.getName().length() - CLASS_FILE_SUFFIX.length()); + String name = baseClass.getPackage().getName() + '.' + simpleName; + + if (isInnerClass(name, baseClass) && parseClassVersion(fileName) == version) { + classes.put(name, f); + } + } + return classes; + } + + private enum IsClassFile implements FilenameFilter { + INSTANCE; + + @Override + public boolean accept(File dir, String name) { + return name.endsWith(CLASS_FILE_SUFFIX); + } + } + + private static boolean isInnerClass(String name, Class<?> baseClass) { + return name.startsWith(baseClass.getName() + "$"); + } + + private static void setCurrentVersion(Class<?> baseClass, int value) { + currentVersion.put(baseClass, value); + } + + /** + * Parse version of the class from the class name. Classes are named in the form of [Name]___[Version] + */ + private static int parseClassVersion(String name) { + int index = name.indexOf(IDENTIFIER); + if (index == -1) { + return 0; + } + return Integer.valueOf(name.substring(index + IDENTIFIER.length(), name.length() - CLASS_FILE_SUFFIX.length())); + } + + private static String stripVersion(String className) { + int index = className.indexOf(IDENTIFIER); + if (index == -1) { + return className; + } + return className.substring(0, index); + } + + public static void resetTimings() { + redefinitionCount = 0; + totalTime = 0; + } + + public static int getRedefinitionCount() { + return redefinitionCount; + } + + public static long getTotalTime() { + return totalTime; + } +} diff --git a/dcevm/src/main/java/org/dcevm/InstrumentationRedefiner.java b/dcevm/src/main/java/org/dcevm/InstrumentationRedefiner.java new file mode 100644 index 00000000..247fbb2e --- /dev/null +++ b/dcevm/src/main/java/org/dcevm/InstrumentationRedefiner.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package org.dcevm; + + +import org.dcevm.agent.InstrumentationAgent; + +import java.io.IOException; +import java.lang.instrument.ClassDefinition; +import java.lang.instrument.Instrumentation; +import java.lang.instrument.UnmodifiableClassException; +import java.util.Map; + +public class InstrumentationRedefiner implements Redefiner { + public void redefineClasses(Map<Class<?>, byte[]> classes) throws ClassNotFoundException, UnmodifiableClassException { + Instrumentation instrumentation = InstrumentationAgent.INSTRUMENTATION; + if (instrumentation == null) { + throw new IllegalStateException("Instrumentation agent is not properly installed!"); + } + + ClassDefinition[] definitions = new ClassDefinition[classes.size()]; + int i = 0; + for (Map.Entry<Class<?>, byte[]> entry : classes.entrySet()) { + definitions[i++] = new ClassDefinition(entry.getKey(), entry.getValue()); + } + instrumentation.redefineClasses(definitions); + } + + @Override + public void close() throws IOException { + // Do nothing. + } +} diff --git a/dcevm/src/main/java/org/dcevm/JDIRedefiner.java b/dcevm/src/main/java/org/dcevm/JDIRedefiner.java new file mode 100644 index 00000000..6fc742d4 --- /dev/null +++ b/dcevm/src/main/java/org/dcevm/JDIRedefiner.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package org.dcevm; + +import com.sun.jdi.Bootstrap; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.VirtualMachine; +import com.sun.jdi.VirtualMachineManager; +import com.sun.jdi.connect.AttachingConnector; +import com.sun.jdi.connect.Connector.Argument; +import com.sun.jdi.connect.IllegalConnectorArgumentsException; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Utility class for performing class redefinition using JDI. + * </li> + * </ul> + * + * @author Thomas Wuerthinger + * @author Kerstin Breiteneder + * @author Christoph Wimberger + * + */ +public class JDIRedefiner implements Redefiner { + + private static final String PORT_ARGUMENT_NAME = "port"; + private static final String TRANSPORT_NAME = "dt_socket"; + + private VirtualMachine vm; + + + /** Port at which to connect to the agent of the VM. **/ + public static final int PORT = 4000; + + public JDIRedefiner(int port) throws IOException { + vm = connect(port); + } + + @Override + public void close() throws IOException { + disconnect(); + } + + private VirtualMachine connect(int port) throws IOException { + VirtualMachineManager manager = Bootstrap.virtualMachineManager(); + + // Find appropiate connector + List<AttachingConnector> connectors = manager.attachingConnectors(); + AttachingConnector chosenConnector = null; + for (AttachingConnector c : connectors) { + if (c.transport().name().equals(TRANSPORT_NAME)) { + chosenConnector = c; + break; + } + } + if (chosenConnector == null) { + throw new IllegalStateException("Could not find socket connector"); + } + + // Set port argument + AttachingConnector connector = chosenConnector; + Map<String, Argument> defaults = connector.defaultArguments(); + Argument arg = defaults.get(PORT_ARGUMENT_NAME); + if (arg == null) { + throw new IllegalStateException("Could not find port argument"); + } + arg.setValue(Integer.toString(port)); + + // Attach + try { + System.out.println("Connector arguments: " + defaults); + return connector.attach(defaults); + } catch (IllegalConnectorArgumentsException e) { + throw new IllegalArgumentException("Illegal connector arguments", e); + } + } + + public void disconnect() { + if (vm != null) { + vm.dispose(); + vm = null; + } + } + + public void redefineClasses(Map<Class<?>, byte[]> classes) { + refreshAllClasses(); + List<ReferenceType> references = vm.allClasses(); + + Map<ReferenceType, byte[]> map = new HashMap<ReferenceType, byte[]>(classes.size()); + for (Map.Entry<Class<?>, byte[]> entry : classes.entrySet()) { + map.put(findReference(references, entry.getKey().getName()), entry.getValue()); + } + vm.redefineClasses(map); + } + + /** + * Call this method before calling allClasses() in order to refresh the JDI state of loaded classes. + * This is necessary because the JDI map of all loaded classes is only updated based on events received over JDWP (network connection) + * and therefore it is not necessarily up-to-date with the real state within the VM. + */ + private void refreshAllClasses() { + try { + Field f = vm.getClass().getDeclaredField("retrievedAllTypes"); + f.setAccessible(true); + f.set(vm, false); + } catch (IllegalArgumentException ex) { + Logger.getLogger(HotSwapTool.class.getName()).log(Level.SEVERE, null, ex); + } catch (IllegalAccessException ex) { + Logger.getLogger(HotSwapTool.class.getName()).log(Level.SEVERE, null, ex); + } catch (NoSuchFieldException ex) { + Logger.getLogger(HotSwapTool.class.getName()).log(Level.SEVERE, null, ex); + } catch (SecurityException ex) { + Logger.getLogger(HotSwapTool.class.getName()).log(Level.SEVERE, null, ex); + } + } + + private static ReferenceType findReference(List<ReferenceType> list, String name) { + for (ReferenceType ref : list) { + if (ref.name().equals(name)) { + return ref; + } + } + throw new IllegalArgumentException("Cannot find corresponding reference for class name '" + name + "'" ); + } +} diff --git a/dcevm/src/main/java/org/dcevm/Redefiner.java b/dcevm/src/main/java/org/dcevm/Redefiner.java new file mode 100644 index 00000000..cd183fe3 --- /dev/null +++ b/dcevm/src/main/java/org/dcevm/Redefiner.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package org.dcevm; + +import java.io.Closeable; +import java.lang.instrument.UnmodifiableClassException; +import java.util.Map; + +/** + * Interface to the class redefinition implementation (JDI-based, Instrumenattion API based) + * + * @author Ivan Dubrov + */ +public interface Redefiner extends Closeable { + void redefineClasses(Map<Class<?>, byte[]> classes) throws ClassNotFoundException, UnmodifiableClassException; +} diff --git a/dcevm/src/main/java/org/dcevm/TestClassAdapter.java b/dcevm/src/main/java/org/dcevm/TestClassAdapter.java new file mode 100644 index 00000000..bd4b2daf --- /dev/null +++ b/dcevm/src/main/java/org/dcevm/TestClassAdapter.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package org.dcevm; + +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.commons.Remapper; +import org.objectweb.asm.commons.RemappingClassAdapter; +import org.objectweb.asm.commons.RemappingMethodAdapter; + +import java.util.Map; + +/** + * @author Ivan Dubrov + */ +public class TestClassAdapter extends RemappingClassAdapter { + /** + * This suffix is automatically removed from the method. + */ + private final static String METHOD_SUFFIX = "___"; + + private boolean isObject; + + public TestClassAdapter(ClassVisitor cv, final Map<String, String> typeMappings) { + super(cv, new Remapper() { + @Override + public String map(String type) { + return typeMappings.containsKey(type) ? typeMappings.get(type) : type; + } + }); + } + + @Override + public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { + // For java/lang/Object redefinition + String newName = remapper.mapType(name); + if (newName.equals("java/lang/Object")) { + superName = null; + isObject = true; + } + super.visit(version, access, name, signature, superName, interfaces); + } + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + return super.visitMethod(access, stripMethodSuffix(name), desc, signature, exceptions); + } + + /** + * Get renamed class name. + * + * @return + */ + public String getClassName() { + return remapper.mapType(className); + } + + protected MethodVisitor createRemappingMethodAdapter( + int access, + String newDesc, + MethodVisitor mv) + { + return new RemappingMethodAdapter(access, newDesc, mv, remapper) { + @Override + public void visitMethodInsn(int opcode, String owner, String name, String desc) { + if (name.equals("<init>") && isObject && owner.equals("java/lang/Object")) { + return; + } + + super.visitMethodInsn(opcode, owner, stripMethodSuffix(name), desc); + } + }; + } + + private static String stripMethodSuffix(String name) { + int pos = name.indexOf(METHOD_SUFFIX); + return (pos != -1) ? name.substring(0, pos) : name; + } +} + diff --git a/dcevm/src/test/java/org/dcevm/test/LightTestSuite.java b/dcevm/src/test/java/org/dcevm/test/LightTestSuite.java new file mode 100644 index 00000000..b5a2af02 --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/LightTestSuite.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test; + +import org.dcevm.test.body.BodyTestSuite; +import org.dcevm.test.eval.EvalTestSuite; +import org.dcevm.test.fields.FieldsTestSuite; +import org.dcevm.test.methods.MethodsTestSuite; +import org.dcevm.test.structural.StructuralTestSuite; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +/** + * Summarizes all available test suites. + * + * @author Thomas Wuerthinger + */ +@RunWith(Suite.class) +@Suite.SuiteClasses({ + BodyTestSuite.class, + EvalTestSuite.class, + MethodsTestSuite.class, + FieldsTestSuite.class, + StructuralTestSuite.class +}) +public class LightTestSuite { +} diff --git a/dcevm/src/test/java/org/dcevm/test/TestUtil.java b/dcevm/src/test/java/org/dcevm/test/TestUtil.java new file mode 100644 index 00000000..7876dac5 --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/TestUtil.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test; + +import junit.framework.Assert; +import org.dcevm.HotSwapTool; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; + +/** + * Utility methods for unit testing. + * + * @author Thomas Wuerthinger + */ +public class TestUtil { + + public static final boolean LIGHT = true; + + public static int assertException(Class exceptionClass, Runnable run) { + + try { + run.run(); + } catch (Throwable t) { + if (t.getClass().equals(exceptionClass)) { + return t.getStackTrace()[0].getLineNumber(); + } + Assert.assertTrue("An exception of type " + t.getClass().getSimpleName() + " instead of " + exceptionClass.getSimpleName() + " has been thrown!", false); + } + + Assert.assertTrue("No exception has been thrown!", false); + return -1; + } + + public static int assertUnsupportedWithLight(Runnable run) { + if (TestUtil.LIGHT) { + return assertUnsupported(run); + } + run.run(); + return -1; + } + + public static int assertUnsupported(Runnable run) { + return assertException(UnsupportedOperationException.class, run); + } + + public static void assertUnsupportedToVersion(final Class clazz, final int version) { + TestUtil.assertUnsupported(new Runnable() { + @Override + public void run() { + HotSwapTool.toVersion(clazz, version); + } + }); + } + + public static void assertUnsupportedToVersionWithLight(final Class clazz, final int version) { + TestUtil.assertUnsupportedWithLight(new Runnable() { + @Override + public void run() { + HotSwapTool.toVersion(clazz, version); + } + }); + } + +} diff --git a/dcevm/src/test/java/org/dcevm/test/body/ArrayTest.java b/dcevm/src/test/java/org/dcevm/test/body/ArrayTest.java new file mode 100644 index 00000000..d82f5010 --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/body/ArrayTest.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.body; + +import org.dcevm.test.TestUtil; +import org.junit.Before; +import org.junit.Test; + +import java.lang.reflect.Array; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * @author Ivan Dubrov + */ +public class ArrayTest { + + public class A { + } + + public class A___1 { + } + + public class B extends A { + } + + public class B___1 extends A { + } + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + @Test + public void testArray() { + Object[] arr = new A[] { new A(), new A() }; + A[] arr2 = new B[] { new B(), new B() }; + A[][] arr3 = new B[10][]; + + __toVersion__(1); + + assertTrue(arr instanceof A[]); + assertTrue(arr instanceof Object[]); + assertEquals(arr.getClass(), Array.newInstance(A.class, 0).getClass()); + + assertTrue(arr2 instanceof B[]); + assertTrue(arr2 instanceof A[]); + assertTrue(arr2 instanceof Object[]); + assertEquals(arr2.getClass(), Array.newInstance(B.class, 0).getClass()); + + assertTrue(arr3 instanceof B[][]); + assertTrue(arr3 instanceof A[][]); + assertTrue(arr3 instanceof Object[][]); + assertEquals(arr3.getClass(), Array.newInstance(B[].class, 0).getClass()); + + __toVersion__(0); + + assertTrue(arr instanceof A[]); + assertTrue(arr instanceof Object[]); + assertEquals(arr.getClass(), Array.newInstance(A.class, 0).getClass()); + + assertTrue(arr2 instanceof B[]); + assertTrue(arr2 instanceof A[]); + assertTrue(arr2 instanceof Object[]); + assertEquals(arr2.getClass(), Array.newInstance(B.class, 0).getClass()); + + assertTrue(arr3 instanceof B[][]); + assertTrue(arr3 instanceof A[][]); + assertTrue(arr3 instanceof Object[][]); + assertEquals(arr3.getClass(), Array.newInstance(B[].class, 0).getClass()); + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/body/BodyTestSuite.java b/dcevm/src/test/java/org/dcevm/test/body/BodyTestSuite.java new file mode 100644 index 00000000..37426aab --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/body/BodyTestSuite.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.body; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +/** + * Class redefinition tests that swap only method bodies and change nothing else. This test cases should also + * run with the current version of HotSpot. + * + * @author Thomas Wuerthinger + */ +@RunWith(Suite.class) +@Suite.SuiteClasses( + { + StaticTest.class, + SimpleStaticTest.class, + MultipleThreadsTest.class, + OldActivationTest.class, + RefactorActiveMethodTest.class, + StressTest.class, + FacTest.class, + FibTest.class, + RedefinePrivateMethodTest.class, + ClassRenamingTestCase.class, + EMCPTest.class, + ArrayTest.class + }) +public class BodyTestSuite { +} diff --git a/dcevm/src/test/java/org/dcevm/test/body/ClassRenamingTestCase.java b/dcevm/src/test/java/org/dcevm/test/body/ClassRenamingTestCase.java new file mode 100644 index 00000000..84488815 --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/body/ClassRenamingTestCase.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package org.dcevm.test.body; + +import org.dcevm.ClassRedefinitionPolicy; +import org.junit.Test; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.junit.Assert.assertEquals; + +/** + * @author Kerstin Breiteneder + * @author Christoph Wimberger + */ +public class ClassRenamingTestCase { + + public static class B { + + public int a() { + return 1; + } + } + + @ClassRedefinitionPolicy(alias = B.class) + public static class A___1 { + + public int a() { + return 2; + } + } + + @Test + public void testRenaming() { + __toVersion__(0); + + B b = new B(); + assertEquals(1, b.a()); + + __toVersion__(1); + + assertEquals(2, b.a()); + + __toVersion__(0); + + assertEquals(1, b.a()); + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/body/EMCPTest.java b/dcevm/src/test/java/org/dcevm/test/body/EMCPTest.java new file mode 100644 index 00000000..0d28d6fe --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/body/EMCPTest.java @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package org.dcevm.test.body; + +import org.dcevm.test.TestUtil; +import org.junit.Test; + +import java.io.PrintStream; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.junit.Assert.assertEquals; + +/** + * EMCP (Equivalent modulo Constant Pool) tests. + * + * @author Thomas Wuerthinger + */ +public class EMCPTest { + + public static class A { + + public static int EMCPReturn() { + change(); + PrintStream s = System.out; + return 1; + } + } + + public static class B { + + public static int b() { + change(); + throw new RuntimeException(); + } + } + + public static class C { + + public static int c() { + changeAndThrow(); + return 0; + } + } + + public static class D { + + private static int value = 1; + + public static int EMCPReturn() { + change3(); + return value; + } + } + + public static class A___1 { + + public static int EMCPReturn() { + change(); + PrintStream s = System.out; + return 1; + } + } + + public static class B___1 { + + public static int b() { + change(); + throw new RuntimeException(); + } + } + + public static class C___1 { + + public static int c() { + changeAndThrow(); + return 0; + } + } + + public static class D___1 { + private static int value = 1; + + public static int EMCPReturn() { + change3(); + return value; + } + } + + public static class D___2 { + private static int value = 1; + + public static int EMCPReturn() { + change3(); + return value; + } + } + + public static class D___3 { + private static int value = 1; + + public static int EMCPReturn() { + change3(); + return value; + } + } + + public static void change() { + + __toVersion__(1); + } + + public static void change3() { + + __toVersion__(1); + __toVersion__(2); + __toVersion__(3); + } + + public static void changeAndThrow() { + + __toVersion__(1); + + throw new RuntimeException(); + } + + + @Test + public void testEMCPReturn() { + __toVersion__(0); + + assertEquals(1, A.EMCPReturn()); + + __toVersion__(0); + + assertEquals(1, A.EMCPReturn()); + + __toVersion__(0); + } + + @Test + public void testEMCPMultiChangeReturn() { + __toVersion__(0); + + assertEquals(1, D.EMCPReturn()); + + __toVersion__(0); + + assertEquals(1, D.EMCPReturn()); + + __toVersion__(0); + } + + @Test + public void testEMCPException() { + __toVersion__(0); + + TestUtil.assertException(RuntimeException.class, new Runnable() { + @Override + public void run() { + B.b(); + } + }); + + __toVersion__(0); + + TestUtil.assertException(RuntimeException.class, new Runnable() { + @Override + public void run() { + B.b(); + } + }); + + __toVersion__(0); + } + + @Test + public void testEMCPExceptionInCallee() { + __toVersion__(0); + + TestUtil.assertException(RuntimeException.class, new Runnable() { + @Override + public void run() { + C.c(); + } + }); + + __toVersion__(0); + + TestUtil.assertException(RuntimeException.class, new Runnable() { + @Override + public void run() { + C.c(); + } + }); + + __toVersion__(0); + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/body/FacTest.java b/dcevm/src/test/java/org/dcevm/test/body/FacTest.java new file mode 100644 index 00000000..832ea7a8 --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/body/FacTest.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.body; + +import org.junit.Before; +import org.junit.Test; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; +import static org.junit.Assert.assertEquals; + +/** + * Recursive implementation of the factorial function using class redefinition. + * + * @author Thomas Wuerthinger + */ +public class FacTest { + + public static abstract class Base { + + protected int calc() { + return calc(__version__()); + } + + public int calcAt(int version) { + __toVersion__(version); + int result = calc(); + __toVersion__(0); + return result; + } + + protected int calc(int version) { + return calc(); + } + } + + public static class Factorial extends Base { + + @Override + protected int calc(int n) { + return n * calcAt(n - 1); + } + } + + public static class Factorial___1 extends Base { + + @Override + protected int calc() { + return 1; + } + } + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + @Test + public void testFac() { + + assert __version__() == 0; + Factorial f = new Factorial(); + + assertEquals(1, f.calcAt(1)); + + assert __version__() == 0; + assertEquals(2, f.calcAt(2)); + + assert __version__() == 0; + assertEquals(6, f.calcAt(3)); + + assert __version__() == 0; + assertEquals(24, f.calcAt(4)); + + assert __version__() == 0; + assertEquals(120, f.calcAt(5)); + + assert __version__() == 0; + assertEquals(479001600, f.calcAt(12)); + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/body/FibTest.java b/dcevm/src/test/java/org/dcevm/test/body/FibTest.java new file mode 100644 index 00000000..c95f2de5 --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/body/FibTest.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.body; + +import org.junit.Before; +import org.junit.Test; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; +import static org.junit.Assert.assertEquals; + +/** + * Recursive implementation of the fibonacci function using class redefinition. + * + * @author Thomas Wuerthinger + */ +public class FibTest { + + public static abstract class Base { + + protected int calc() { + return calc(__version__()); + } + + public int calcAt(int version) { + __toVersion__(version); + int result = calc(); + __toVersion__(0); + return result; + } + + protected int calc(int version) { + return calc(); + } + } + + public static class Fib extends Base { + + @Override + protected int calc(int n) { + return calcAt(n - 1) + calcAt(n - 2); + } + } + + public static class Fib___1 extends Base { + + @Override + protected int calc() { + return 1; + } + } + + public static class Fib___2 extends Base { + + @Override + protected int calc() { + return 2; + } + } + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + @Test + public void testFib() { + + // 0 1 2 3 4 5 + // 1 1 2 3 5 8 + assert __version__() == 0; + Fib f = new Fib(); + + assertEquals(1, f.calcAt(1)); + + assert __version__() == 0; + assertEquals(2, f.calcAt(2)); + + assert __version__() == 0; + assertEquals(3, f.calcAt(3)); + + assert __version__() == 0; + assertEquals(5, f.calcAt(4)); + + assert __version__() == 0; + assertEquals(8, f.calcAt(5)); + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/body/MultipleThreadsTest.java b/dcevm/src/test/java/org/dcevm/test/body/MultipleThreadsTest.java new file mode 100644 index 00000000..4966a2fc --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/body/MultipleThreadsTest.java @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.body; + +import org.junit.Before; +import org.junit.Test; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * Class for testing redefining methods of classes that extend the Thread class. In the test setup the run method + * calls the doit method in a loop until this methods returns false. + * + * @author Thomas Wuerthinger + */ +public class MultipleThreadsTest { + + public static final int COUNT = 10; + + // Version 0 + public static class A extends Thread { + + private int value; + private int value2; + private boolean flag = false; + + @Override + public void run() { + while (doit()) { + flag = false; + } + } + + public boolean doit() { + if (flag) { + throw new RuntimeException("Must not reach here"); + } + flag = true; + try { + Thread.sleep(1); + } catch (InterruptedException e) { + } + + value++; + return true; + } + + public int getValue() { + return value; + } + + public int getValue2() { + return value2; + } + } + + // Version 1 + public static class A___1 extends Thread { + + private int value; + private int value2; + private boolean flag = false; + + @Override + public void run() { + while (doit()) { + flag = false; + } + } + + public boolean doit() { + if (flag) { + throw new RuntimeException("Must not reach here"); + } + flag = true; + try { + Thread.sleep(1); + } catch (InterruptedException e) { + } + + value2++; + return true; + } + + public int getValue() { + return value; + } + + public int getValue2() { + return value2; + } + } + + // Version 2 + public static class A___2 extends Thread { + + private int value; + private int value2; + private boolean flag = false; + + @Override + public void run() { + while (doit()) { + flag = false; + } + } + + public boolean doit() { + return false; + } + + public int getValue() { + return value; + } + + public int getValue2() { + return value2; + } + } + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + @Test + public void testOneThread() { + test(1); + } + + @Test + public void testThreads() { + test(COUNT); + } + + private void test(int count) { + + assert __version__() == 0; + + A[] arr = new A[count]; + for (int i = 0; i < count; i++) { + arr[i] = new A(); + arr[i].start(); + } + + try { + Thread.sleep(500); + } catch (InterruptedException e) { + } + + for (int i = 0; i < count; i++) { + //assertTrue(arr[i].getValue() > 0); + } + + __toVersion__(1); + + try { + Thread.sleep(500); + } catch (InterruptedException e) { + } + + for (int i = 0; i < count; i++) { + assertTrue(arr[i].getValue2() > 0); + } + + __toVersion__(2); + + try { + Thread.sleep(500); + } catch (InterruptedException e) { + } + + + for (int i = 0; i < count; i++) { + assertFalse(arr[i].isAlive()); + } + + __toVersion__(0); + + + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/body/OldActivationTest.java b/dcevm/src/test/java/org/dcevm/test/body/OldActivationTest.java new file mode 100644 index 00000000..3ad7f400 --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/body/OldActivationTest.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.body; + +import org.junit.Before; +import org.junit.Test; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; +import static org.junit.Assert.assertEquals; + +/** + * Stress test for the number of old activations on the stack. In the test setup 10 different versions of the method A.value will be on the stack. + * + * @author Thomas Wuerthinger + */ +public class OldActivationTest { + + // Version 0 + public static class A { + + public int value() { + __toVersion__(1); + return 1 + this.value(); + } + } + + // Version 1 + public static class A___1 { + + public int value() { + __toVersion__(2); + return 2 + this.value(); + } + } + + // Version 2 + public static class A___2 { + + public int value() { + __toVersion__(3); + return 3 + this.value(); + } + } + + // Version 3 + public static class A___3 { + + public int value() { + __toVersion__(4); + return 4 + this.value(); + } + } + + // Version 4 + public static class A___4 { + + public int value() { + __toVersion__(5); + return 5 + this.value(); + } + } + + // Version 5 + public static class A___5 { + + public int value() { + __toVersion__(6); + return 6 + this.value(); + } + } + + // Version 6 + public static class A___6 { + + public int value() { + __toVersion__(7); + return 7 + this.value(); + } + } + + // Version 7 + public static class A___7 { + + public int value() { + __toVersion__(8); + return 8 + this.value(); + } + } + + // Version 8 + public static class A___8 { + + public int value() { + __toVersion__(9); + return 9 + this.value(); + } + } + + // Version 9 + public static class A___9 { + + public int value() { + __toVersion__(0); + return 10; + } + } + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + @Test + public void testOldActivationTest() { + + assert __version__() == 0; + + A a = new A(); + + assertEquals(1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10, a.value()); + assert __version__() == 0; + + __toVersion__(1); + assertEquals(2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10, a.value()); + assert __version__() == 0; + + __toVersion__(8); + assertEquals(9 + 10, a.value()); + assert __version__() == 0; + + __toVersion__(4); + assertEquals(5 + 6 + 7 + 8 + 9 + 10, a.value()); + assert __version__() == 0; + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/body/RedefinePrivateMethodTest.java b/dcevm/src/test/java/org/dcevm/test/body/RedefinePrivateMethodTest.java new file mode 100644 index 00000000..935907fa --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/body/RedefinePrivateMethodTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.body; + +import org.junit.Before; +import org.junit.Test; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; +import static org.junit.Assert.assertEquals; + +/** + * Tests redefinition of a class such that old code still accesses a redefined private method. + * + * @author Thomas Wuerthinger + */ +public class RedefinePrivateMethodTest { + + // Version 0 + public static class A { + + public int foo() { + int result = bar(); + __toVersion__(1); + result += bar(); + return result; + } + + private int bar() { + return 1; + } + } + + // Version 1 + public static class A___1 { + + public int foo() { + return -1; + } + + private int bar() { + return 2; + } + } + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + @Test + public void testRedefinePrivateMethod() { + + assert __version__() == 0; + + A a = new A(); + + assertEquals(3, a.foo()); + + assert __version__() == 1; + + assertEquals(-1, a.foo()); + + __toVersion__(0); + + assertEquals(3, a.foo()); + + assert __version__() == 1; + + assertEquals(-1, a.foo()); + + __toVersion__(0); + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/body/RefactorActiveMethodTest.java b/dcevm/src/test/java/org/dcevm/test/body/RefactorActiveMethodTest.java new file mode 100644 index 00000000..4dd433ce --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/body/RefactorActiveMethodTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.body; + +import org.junit.Before; +import org.junit.Test; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; +import static org.junit.Assert.assertEquals; + +/** + * @author Thomas Wuerthinger + */ +public class RefactorActiveMethodTest { + + // Version 0 + public static class A { + + public int value() { + __toVersion__(1); + return 5; + } + + public int secondValue() { + return 1; + } + } + + // Version 1 + public static class A___1 { + + public int value() { + return secondValue() * 2; + } + + public int secondValue() { + return 2; + } + } + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + @Test + public void testActiveMethodReplacement() { + + assert __version__() == 0; + + A a = new A(); + + assertEquals(5, a.value()); + + assert __version__() == 1; + + assertEquals(2, a.secondValue()); + assertEquals(4, a.value()); + assertEquals(2, a.secondValue()); + + assert __version__() == 1; + + __toVersion__(0); + + assertEquals(1, a.secondValue()); + assertEquals(5, a.value()); + assertEquals(4, a.value()); + + __toVersion__(0); + + assertEquals(1, a.secondValue()); + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/body/SimpleStaticTest.java b/dcevm/src/test/java/org/dcevm/test/body/SimpleStaticTest.java new file mode 100644 index 00000000..a456381d --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/body/SimpleStaticTest.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.body; + +import org.dcevm.test.TestUtil; +import org.junit.Before; +import org.junit.Test; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; +import static org.junit.Assert.assertEquals; + +/** + * @author Thomas Wuerthinger + */ +public class SimpleStaticTest { + + @Before + public void setUp() throws Exception { + __toVersion__(0); + + // E and Helper must be loaded and initialized + E e = new E(); + Helper h = new Helper(); + } + + // Version 0 + + public static class Helper { + public static int getIntegerField() { + return E.integerField; + } + + public static void setIntegerField(int x) { + E.integerField = x; + } + + public static int getFinalIntegerField() { + return E.finalIntegerField; + } + } + + public static class E { + public static int integerField = 10; + + public static E self = new E(); + + // javac will generate "ConstantValue" attribute for this field! + public static final int finalIntegerField = 7; + } + + public static class E___1 { + public static E___1 self = new E___1(); + } + + // Version 1 + public static class E___2 { + public static int integerField = 10; + + // javac will generate "ConstantValue" attribute for this field! + public static final int finalIntegerField = 7; + } + + @Test + public void testSimpleNewStaticField() { + + assert __version__() == 0; + + __toVersion__(1); + + TestUtil.assertException(NoSuchFieldError.class, new Runnable() { + @Override + public void run() { + Helper.getIntegerField(); + } + }); + + __toVersion__(2); + + assertEquals(0, Helper.getIntegerField()); + assertEquals(7, Helper.getFinalIntegerField()); + Helper.setIntegerField(1000); + assertEquals(1000, Helper.getIntegerField()); + + __toVersion__(1); + + TestUtil.assertException(NoSuchFieldError.class, new Runnable() { + @Override + public void run() { + Helper.getIntegerField(); + } + }); + + __toVersion__(2); + + assertEquals(0, Helper.getIntegerField()); + assertEquals(7, Helper.getFinalIntegerField()); + Helper.setIntegerField(1000); + assertEquals(1000, Helper.getIntegerField()); + + __toVersion__(0); + + assertEquals(7, Helper.getFinalIntegerField()); + assertEquals(1000, Helper.getIntegerField()); + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/body/StaticTest.java b/dcevm/src/test/java/org/dcevm/test/body/StaticTest.java new file mode 100644 index 00000000..b4369b77 --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/body/StaticTest.java @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.body; + +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static junit.framework.Assert.assertNull; +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * @author Thomas Wuerthinger + */ +public class StaticTest { + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + // Version 0 + + + public static class Helper { + public static int getAdditionalField() { + return -1; + } + + public static void setAdditionalField(int x) { + + } + } + + public static class A { + + public static int value() { + return 1; + } + } + + public static class B { + + public static int value() { + return 2; + } + } + + public static class C { + static { + System.out.println("Static initializer of C"); + } + + public static int value = 5; + } + + public static class D { + public static List objectField = new ArrayList(); + public static int[] arrayField = new int[10]; + public static int integerField = 5; + public static char characterField = 6; + public static short shortField = 7; + public static double doubleField = 1.0; + public static float floatField = 2.0f; + public static long longField = 8; + public static boolean booleanField = true; + } + + // Version 1 + public static class A___1 { + + public static int value() { + return B.value() * 2; + } + } + + // Version 2 + public static class B___2 { + + public static int value() { + return 3; + } + } + + // Version 3 + public static class A___3 { + + public static int value() { + return 5; + } + } + + public static class B___3 { + + public static int value() { + return A.value() * 2; + } + } + + // Version 4 + public static class C___4 { + + static { + System.out.println("Static initializer of C-4"); + } + + public static int value = 6; + } + + public static class Helper___5 { + public static int getAdditionalField() { + return D___5.additionalField; + } + + public static void setAdditionalField(int x) { + D___5.additionalField = x; + } + } + + public static class D___5 { + public static int additionalField; + + public static List objectField; + public static long longField; + public static short shortField = 10; + public static float floatField; + public static int[] arrayField; + public static int integerField; + public static char characterField; + public static double doubleField; + public static boolean booleanField; + } + + public static class E { + public static Class<?> eClass = E.class; + public static Class<?> eClassArr = E[].class; + public static Class<?> eClassNull; + public static Class<?> eClassPrim = Integer.TYPE; + } + + public static class E___6 { + public static Class<?> eClass; + public static Class<?> eClassArr; + public static Class<?> eClassNull; + public static Class<?> eClassPrim; + } + + @Test + public void testBase() { + + assert __version__() == 0; + + + assertEquals(1, A.value()); + assertEquals(2, B.value()); + + __toVersion__(1); + + assertEquals(4, A.value()); + assertEquals(2, B.value()); + + __toVersion__(2); + + assertEquals(6, A.value()); + assertEquals(3, B.value()); + + __toVersion__(3); + + assertEquals(5, A.value()); + assertEquals(10, B.value()); + + __toVersion__(0); + + assertEquals(1, A.value()); + assertEquals(2, B.value()); + } + + @Test + public void testStaticField() { + + assert __version__() == 0; + assertEquals(5, C.value); + + __toVersion__(4); + assertEquals(5, C.value); + + __toVersion__(0); + assertEquals(5, C.value); + } + + @Test + public void testStaticFieldUpdated() { + assert __version__() == 0; + assertEquals(E.class, E.eClass); + assertNull(E.eClassNull); + assertEquals(E[].class, E.eClassArr); + + __toVersion__(6); + assertEquals(E.class, E.eClass); + assertNull(E.eClassNull); + assertEquals(E[].class, E.eClassArr); + } + + @Test + public void testManyStaticFields() { + + assert __version__() == 0; + assertTrue(D.objectField != null); + assertTrue(D.arrayField != null); + assertEquals(5, D.integerField); + assertEquals(6, D.characterField); + assertEquals(7, D.shortField); + assertEquals(1.0, D.doubleField, 0.0); + assertEquals(2.0f, D.floatField, 0.0); + assertEquals(8, D.longField); + assertEquals(true, D.booleanField); + + __toVersion__(5); + assertTrue(D.objectField != null); + assertTrue(D.arrayField != null); + assertEquals(5, D.integerField); + assertEquals(6, D.characterField); + assertEquals(7, D.shortField); + assertEquals(1.0, D.doubleField, 0.0); + assertEquals(2.0f, D.floatField, 0.0); + assertEquals(8, D.longField); + assertEquals(true, D.booleanField); + + assertEquals(0, Helper.getAdditionalField()); + Helper.setAdditionalField(1000); + assertEquals(1000, Helper.getAdditionalField()); + + + __toVersion__(0); + + assertTrue(D.objectField != null); + assertTrue(D.arrayField != null); + assertEquals(5, D.integerField); + assertEquals(6, D.characterField); + assertEquals(7, D.shortField); + assertEquals(1.0, D.doubleField, 0.0); + assertEquals(2.0f, D.floatField, 0.0); + assertEquals(8, D.longField); + assertEquals(true, D.booleanField); + + __toVersion__(5); + assertTrue(D.objectField != null); + assertTrue(D.arrayField != null); + assertEquals(5, D.integerField); + assertEquals(6, D.characterField); + assertEquals(7, D.shortField); + assertEquals(1.0, D.doubleField, 0.0); + assertEquals(2.0f, D.floatField, 0.0); + assertEquals(8, D.longField); + assertEquals(true, D.booleanField); + + assertEquals(0, Helper.getAdditionalField()); + + __toVersion__(0); + assertTrue(D.objectField != null); + assertTrue(D.arrayField != null); + assertEquals(5, D.integerField); + assertEquals(6, D.characterField); + assertEquals(7, D.shortField); + assertEquals(1.0, D.doubleField, 0.0); + assertEquals(2.0f, D.floatField, 0.0); + assertEquals(8, D.longField); + assertEquals(true, D.booleanField); + + } + + +} diff --git a/dcevm/src/test/java/org/dcevm/test/body/StressTest.java b/dcevm/src/test/java/org/dcevm/test/body/StressTest.java new file mode 100644 index 00000000..3d955810 --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/body/StressTest.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.body; + +import org.junit.Before; +import org.junit.Test; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; +import static org.junit.Assert.assertEquals; + +/** + * @author Thomas Wuerthinger + */ +public class StressTest { + + public final static int COUNT = 10; + + // Version 0 + public static class A { + + public int value() { + return 1; + } + } + + // Version 1 + public static class A___1 { + + public int value() { + return 2; + } + } + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + @Test + public void testStressSwap() { + + assert __version__() == 0; + + A a = new A(); + + for (int i = 0; i < COUNT; i++) { + + assertEquals(1, a.value()); + + __toVersion__(1); + + assertEquals(2, a.value()); + + __toVersion__(0); + } + + assertEquals(1, a.value()); + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/eval/AddingInterfaceTest.java b/dcevm/src/test/java/org/dcevm/test/eval/AddingInterfaceTest.java new file mode 100644 index 00000000..a3bec93d --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/eval/AddingInterfaceTest.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.eval; + +import org.dcevm.test.TestUtil; +import org.junit.Before; +import org.junit.Test; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; + +/** + * Adds an implemented interface to a class and tests whether an instance of this class can then really be treated as an instance of the interface. + * Additionally, performs performance measurements of a call to this interface compared to a proxy object. + * + * @author Thomas Wuerthinger + */ +public class AddingInterfaceTest { + + @Before + public void setUp() throws Exception { + __toVersion__(0); + assert __version__() == 0; + } + + public static class A { + + public int getValue() { + return 1; + } + } + + public static interface I { + + public int getValue(); + } + + public static class A___1 implements I { + + @Override + public int getValue() { + return 1; + } + } + + public static class Proxy implements I { + + private A a; + + public Proxy(A a) { + this.a = a; + } + + @Override + public int getValue() { + return a.getValue(); + } + } + + @Test + public void testAddInterface() { + + A a = new A(); + Proxy p = new Proxy(a); + + final int N = 100000; + final int Z = 1; + + + __toVersion__(1); + I i = (I) a; + + long startTime = System.currentTimeMillis(); + for (int j = 0; j < Z; j++) { + calculateSum(N, i); + } + long time = System.currentTimeMillis() - startTime; + System.out.println(time); + + // Must set to null, otherwise local variable i would violate type safety + i = null; + + TestUtil.assertUnsupportedToVersionWithLight(AddingInterfaceTest.class, 0); + + startTime = System.currentTimeMillis(); + for (int j = 0; j < Z; j++) { + calculateSum(N, p); + } + time = System.currentTimeMillis() - startTime; + System.out.println(time); + } + + public int calculateSum(int n, I i) { + int sum = 0; + for (int j = 0; j < n; j++) { + sum += i.getValue(); + } + return sum; + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/eval/EvalTestSuite.java b/dcevm/src/test/java/org/dcevm/test/eval/EvalTestSuite.java new file mode 100644 index 00000000..f9baf6c9 --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/eval/EvalTestSuite.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.eval; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +/** + * Tests used for evaluation purposes (especially performance measurements). + * + * @author Thomas Wuerthinger + */ +@RunWith(Suite.class) +@Suite.SuiteClasses({ + FractionTest.class, + GeometryScenario.class, + AddingInterfaceTest.class +}) +public class EvalTestSuite { +} diff --git a/dcevm/src/test/java/org/dcevm/test/eval/FractionTest.java b/dcevm/src/test/java/org/dcevm/test/eval/FractionTest.java new file mode 100644 index 00000000..37ed44f6 --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/eval/FractionTest.java @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.eval; + +import org.dcevm.HotSwapTool; +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; + +/** + * @author Thomas Wuerthinger + */ +public class FractionTest { + + @Before + public void setUp() throws Exception { + __toVersion__(0); + assert __version__() == 0; + } + + // Version 0 + public static class NoChange { + + int i1; + int i2; + int i3; + Object o1; + Object o2; + Object o3; + } + + public static class Change { + + int i1; + int i2; + int i3; + Object o1; + Object o2; + Object o3; + } + + // Version 1 + public static class Change___1 { + + int i1; + int i2; + int i3; + Object o1; + Object o2; + Object o3; + Object o4; + } + + // Version 2 + public static class Change___2 { + + int i1; + int i2; + int i3; + Object o1; + } + + // Version 3 + public static class Change___3 { + + int i3; + int i1; + int i2; + Object o3; + Object o1; + Object o2; + } + + // Version 3 + public static class Change___4 { + + int i1; + int i2; + int i3; + Object o1; + Object o2; + Object o3; + } + + // Version 2 + public static class Change___5 { + + } + + private static List<Long> measurements = new ArrayList<Long>(); + private final int BASE = 10; + private Object[] objects; + + private void clear() { + objects = null; + System.gc(); + System.gc(); + __toVersion__(0); + System.gc(); + System.gc(); + + } + + private void init(int count, int percent) { + objects = new Object[count]; + int changed = 0; + int unchanged = 0; + for (int k = 0; k < count; k++) { + if ((count / BASE) * percent <= k/* && k >= 200000*/) { + objects[k] = new NoChange(); + unchanged++; + } else { + objects[k] = new Change(); + changed++; + } + } + + System.gc(); + + System.out.println(changed + " changed objects allocated"); + } + + @Test + public void testBase() { + + assert __version__() == 0; + + final int N = 1; + final int INC = 4; + final int SIZE = 4000; + + int[] benchmarking = new int[]{SIZE}; + int base = BASE; + int start = 0; + + MicroBenchmark[] benchmarks = new MicroBenchmark[]{new GCMicroBenchmark(), new IncreaseMicroBenchmark(), new DecreaseMicroBenchmark(), new ReorderMicroBenchmark(), new NoRealChangeMicroBenchmark(), new BigDecreaseMicroBenchmark()}; + + clear(); + for (int k = 0; k < N; k++) { + for (MicroBenchmark m : benchmarks) { + for (int i : benchmarking) { + System.out.println(m.getClass().getName() + " with " + i + " objects"); + for (int j = start; j <= base; j += INC) { + System.out.println(j); + m.init(i); + init(i, j); + m.doit(i, measurements); + clear(); + } + } + } + } + + System.out.println("Results:"); + for (long l : measurements) { + System.out.println(l); + } + measurements.clear(); + } +} + +abstract class MicroBenchmark { + + public void init(int count) { + } + + public abstract void doit(int count, List<Long> measurements); +} + +class GCMicroBenchmark extends MicroBenchmark { + + @Override + public void doit(int count, List<Long> measurements) { + long startTime = System.currentTimeMillis(); + System.gc(); + long curTime = System.currentTimeMillis() - startTime; + measurements.add(curTime); + } +} + +class IncreaseMicroBenchmark extends MicroBenchmark { + + @Override + public void doit(int count, List<Long> measurements) { + HotSwapTool.resetTimings(); + __toVersion__(1); + measurements.add(HotSwapTool.getTotalTime()); + } +} + +class DecreaseMicroBenchmark extends MicroBenchmark { + + @Override + public void doit(int count, List<Long> measurements) { + HotSwapTool.resetTimings(); + __toVersion__(2); + measurements.add(HotSwapTool.getTotalTime()); + } +} + +class ReorderMicroBenchmark extends MicroBenchmark { + + @Override + public void doit(int count, List<Long> measurements) { + HotSwapTool.resetTimings(); + __toVersion__(3); + measurements.add(HotSwapTool.getTotalTime()); + } +} + +class NoRealChangeMicroBenchmark extends MicroBenchmark { + + @Override + public void doit(int count, List<Long> measurements) { + HotSwapTool.resetTimings(); + __toVersion__(4); + measurements.add(HotSwapTool.getTotalTime()); + } +} + +class BigDecreaseMicroBenchmark extends MicroBenchmark { + + @Override + public void doit(int count, List<Long> measurements) { + HotSwapTool.resetTimings(); + __toVersion__(5); + measurements.add(HotSwapTool.getTotalTime()); + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/eval/GeometryScenario.java b/dcevm/src/test/java/org/dcevm/test/eval/GeometryScenario.java new file mode 100644 index 00000000..f671b6ca --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/eval/GeometryScenario.java @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package org.dcevm.test.eval; + +import org.dcevm.test.TestUtil; +import org.junit.Before; +import org.junit.Test; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; +import static org.junit.Assert.assertEquals; + +/** + * A small geometry example application including a Point and a Rectangle class. + * + * @author Thomas Wuerthinger + */ +public class GeometryScenario { + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + // Version 0 + public static class Point { + + private int x; + private int y; + + public Point(int x, int y) { + this.x = x; + this.y = y; + } + + public boolean isBottomRightOf(Point p) { + return p.x >= x && p.y >= y; + } + + public boolean isTopLeftOf(Point p) { + return p.x <= x && p.y <= y; + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + } + + public static interface IFigure { + + public boolean isHitAt(Point p); + } + + public static class Rectangle { + + private Point topLeft; + private Point bottomRight; + + public Rectangle(Point p1, Point p2) { + topLeft = p1; + bottomRight = p2; + } + + public boolean isHitAt(Point p) { + return p.isBottomRightOf(topLeft) && !p.isTopLeftOf(bottomRight); + } + + public Point getTopLeft() { + return topLeft; + } + + public Point getBottomRight() { + return bottomRight; + } + + public static Rectangle create(Point p) { + return (Rectangle) (Object) (new Rectangle___1(p)); + } + } + + // Version 1 + public static class Rectangle___1 implements IFigure { + + private Point topLeft; + private Point center; + private Point bottomRight; + + public Point getCenter() { + return center; + } + + public Rectangle___1(Point p) { + topLeft = p; + bottomRight = p; + } + + @Override + public boolean isHitAt(Point p) { + return p.isBottomRightOf(topLeft) && !p.isTopLeftOf(bottomRight); + } + + public Point getTopLeft() { + return topLeft; + } + + public Point getBottomRight() { + return bottomRight; + } + + public static Rectangle create(Point p) { + return (Rectangle) (Object) (new Rectangle___1(p)); + } + } + + public static class Point___1 { + + private char x1; + private int y; + private char x2; + + public boolean isBottomRightOf(Point p) { + return p.x >= x1 && p.y >= y; + } + + public boolean isTopLeftOf(Point p) { + return p.x <= x1 && p.y <= y; + } + + public int getY() { + return y; + } + + public int getX() { + return x1; + } + + public char getX2() { + return x2; + } + } + + @Test + public void testContructorChange() { + + assert __version__() == 0; + + final Point p1 = new Point(1, 2); + final Point p2 = new Point(3, 4); + final Rectangle r1 = new Rectangle(p1, p2); + + assertEquals(1, p1.getX()); + assertEquals(2, p1.getY()); + assertEquals(3, p2.getX()); + assertEquals(4, p2.getY()); + assertEquals(p1, r1.getTopLeft()); + assertEquals(p2, r1.getBottomRight()); + + __toVersion__(1); + + final Rectangle r4 = Rectangle.create(p1); + assertEquals(0, p1.getX()); + assertEquals(2, p1.getY()); + assertEquals(0, p2.getX()); + assertEquals(4, p2.getY()); + assertEquals(p1, r4.getTopLeft()); + assertEquals(p1, r4.getBottomRight()); + + TestUtil.assertUnsupportedWithLight(new Runnable() { + + @Override + public void run() { + __toVersion__(0); + assertEquals(0, p1.getX()); + assertEquals(2, p1.getY()); + assertEquals(0, p2.getX()); + assertEquals(4, p2.getY()); + assertEquals(p1, r4.getTopLeft()); + assertEquals(p1, r4.getBottomRight()); + } + }); + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/fields/ComplexFieldTest.java b/dcevm/src/test/java/org/dcevm/test/fields/ComplexFieldTest.java new file mode 100644 index 00000000..e7562349 --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/fields/ComplexFieldTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.fields; + +import org.junit.Before; +import org.junit.Test; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; +import static org.junit.Assert.assertEquals; + +/** + * Complex field test. + * + * @author Thomas Wuerthinger + */ +public class ComplexFieldTest { + + // Version 0 + public static class A { + public byte byteFld = 10; + public short shortFld = 20; + public int intFld = 30; + public long longFld = 40L; + public float floatFld = 50.2F; + public double doubleFld = 60.3D; + public char charFld = 'b'; + public boolean booleanFld = true; + public String stringFld = "OLD"; + } + + // Version 1 + public static class A___1 { + public byte byteFld = 11; + public short shortFld = 22; + public int intFld = 33; + public long longFld = 44L; + public float floatFld = 55.5F; + public double doubleFld = 66.6D; + public char charFld = 'c'; + public boolean booleanFld = false; + public String stringFld = "NEW"; + + // completely new instance fields are below + public int intComplNewFld = 333; + public long longComplNewFld = 444L; + public String stringComplNewFld = "completely new String field"; + } + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + /** + * Checks that the given object is unmodified (i.e. the values of the fields are correct) + * + * @param a the object to be checked + */ + private void assertObjectOK(A a) { + assertEquals(10, a.byteFld); + assertEquals(20, a.shortFld); + assertEquals(30, a.intFld); + assertEquals(40L, a.longFld); + assertEquals(50.2F, a.floatFld, 0.01); + assertEquals(60.3D, a.doubleFld, 0.01); + assertEquals('b', a.charFld); + assertEquals(true, a.booleanFld); + assertEquals("OLD", a.stringFld); + } + + @Test + public void testComplexFieldChange() { + assert __version__() == 0; + A a = new A(); + assertObjectOK(a); + __toVersion__(1); + assertObjectOK(a); + __toVersion__(0); + assertObjectOK(a); + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/fields/EnumTest.java b/dcevm/src/test/java/org/dcevm/test/fields/EnumTest.java new file mode 100644 index 00000000..a5443bef --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/fields/EnumTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.fields; + +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +/** + * @author Ivan Dubrov + */ +public class EnumTest { + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + static enum A { + FIRST, + SECOND; + } + + static enum A___1 { + SECOND, + THIRD, + FOURTH; + } + + @Test + @Ignore + public void testEnumFields() throws Exception { + assertEquals(2, A.values().length); + assertNotNull(A.values()[0]); + assertNotNull(A.values()[1]); + + __toVersion__(1); + + assertEquals(3, A.values().length); + assertNotNull(A.values()[0]); + assertNotNull(A.values()[1]); + assertNotNull(A.values()[2]); + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/fields/FieldAlignmentTest.java b/dcevm/src/test/java/org/dcevm/test/fields/FieldAlignmentTest.java new file mode 100644 index 00000000..ebd47771 --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/fields/FieldAlignmentTest.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.fields; + +import org.junit.Before; +import org.junit.Test; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; + +/** + * Complex field test. + * + * @author Ivan Dubrov + */ +public class FieldAlignmentTest { + + // Version 0 + public static class A { + } + + // Version 1 + public static class A___1 { + public boolean booleanFld; // note: gap betweer booleanFld and stringFld, should be properly filled. + public String stringFld = "NEW"; + } + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + @Test + public void testComplexFieldChange() { + assert __version__() == 0; + A a = new A(); + __toVersion__(1); + System.gc(); // induce GC to verify that gap is properly filled + __toVersion__(0); + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/fields/FieldChangedOrderTest.java b/dcevm/src/test/java/org/dcevm/test/fields/FieldChangedOrderTest.java new file mode 100644 index 00000000..99f03afa --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/fields/FieldChangedOrderTest.java @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.fields; + +import org.junit.Before; +import org.junit.Test; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; +import static org.junit.Assert.assertEquals; + +/** + * Test that changes the order of two int fields. + * + * @author Thomas Wuerthinger + */ +public class FieldChangedOrderTest { + + // Version 0 + public static class A { + + public int value1; + public int value2; + + public A() { + value1 = 1; + value2 = 2; + } + + public int getValue1() { + return value1; + } + + public int getValue2() { + return value2; + } + } + + public static class B { + + public static int getStaticValue1(A a) { + return a.value1; + } + + public static int getStaticValue2(A a) { + return a.value2; + } + } + + // Version 1 + public static class A___1 { + + public int value2; + public int value1; + + public int getValue1() { + return value1; + } + + public int getValue2() { + return value2; + } + } + + public static class B___1 { + + public static int getStaticValue1(A a) { + return a.value1; + } + + public static int getStaticValue2(A a) { + return a.value2; + } + } + + // Version 2 + public static class A___2 { + + public int tmp1; + public int value2; + public int tmp2; + public int value1; + public int tmp3; + + public int getValue1() { + return value1; + } + + public int getValue2() { + return value2; + } + } + + // Version 3 + public static class A___3 { + + public int tmp1; + public int value2; + + public int getValue1() { + return tmp1; + } + + public int getValue2() { + return value2; + } + } + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + @Test + public void testRenameField() { + assert __version__() == 0; + A a = new A(); + assertObjectOK(a); + __toVersion__(3); + assertEquals(0, a.getValue1()); + assertEquals(2, a.getValue2()); + __toVersion__(0); + assertEquals(0, a.getValue1()); + assertEquals(2, a.getValue2()); + } + + @Test + public void testSimpleOrderChange() { + assert __version__() == 0; + A a = new A(); + assertObjectOK(a); + __toVersion__(1); + assertObjectOK(a); + __toVersion__(0); + assertObjectOK(a); + } + + /** + * Checks that the given object is unmodified (i.e. the values of the fields are correct) + * + * @param a the object to be checked + */ + private void assertObjectOK(A a) { + assertEquals(1, a.getValue1()); + assertEquals(2, a.getValue2()); + assertEquals(1, B.getStaticValue1(a)); + assertEquals(2, B.getStaticValue2(a)); + assertEquals(1, a.value1); + assertEquals(2, a.value2); + } + + @Test + public void testSimpleOrderChangeWithNewTempFields() { + assert __version__() == 0; + A a = new A(); + assertObjectOK(a); + __toVersion__(2); + assertObjectOK(a); + __toVersion__(0); + assertObjectOK(a); + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/fields/FieldModificationTest.java b/dcevm/src/test/java/org/dcevm/test/fields/FieldModificationTest.java new file mode 100644 index 00000000..3529e6ad --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/fields/FieldModificationTest.java @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.fields; + +import org.junit.Before; +import org.junit.Test; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; +import static org.junit.Assert.assertEquals; + +/** + * @author Thomas Wuerthinger + */ +public class FieldModificationTest { + + // Version 0 + public static class A { + + public int val0; + public int val1; + public int val2; + public int val3; + public int val4; + public int val5; + public int val6; + public int val7; + + public void increaseAllByOne() { + val0++; + val1++; + val2++; + val3++; + val4++; + val5++; + val6++; + val7++; + } + + public int sum() { + return val0 + val1 + val2 + val3 + val4 + val5 + val6 + val7; + } + } + + // Version 1 + public static class A___1 { + + public int val0; + + public void increaseAllByOne() { + val0++; + } + + public int sum() { + return val0; + } + } + + // Version 2 + public static class A___2 { + + public int val0; + public int val1; + public int val2; + public int val3; + public int val4; + public int val5; + public int val6; + public int val7; + public int val8; + public int val9; + public int val10; + public int val11; + public int val12; + public int val13; + public int val14; + public int val15; + + public int sum() { + return val0 + val1 + val2 + val3 + val4 + val5 + val6 + val7 + val8 + val9 + val10 + val11 + val12 + val13 + val14 + val15; + } + + public void increaseAllByOne() { + val0++; + val1++; + val2++; + val3++; + val4++; + val5++; + val6++; + val7++; + val8++; + val9++; + val10++; + val11++; + val12++; + val13++; + val14++; + val15++; + } + } + + // Version 3 + public static class A___3 { + + public int val6; + public int val0; + public int val7; + public int val1; + public int val2; + public int val5; + public int val3; + public int val4; + } + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + @Test + public void testReorder() { + + A a = new A(); + + a.val0 = 0; + a.val1 = 1; + a.val2 = 2; + a.val3 = 3; + a.val4 = 4; + a.val5 = 5; + a.val6 = 6; + a.val7 = 7; + } + + @Test + public void testIncreaseFirst() { + + A a = new A(); + + a.val0 = 0; + a.val1 = 1; + a.val2 = 2; + a.val3 = 3; + a.val4 = 4; + a.val5 = 5; + a.val6 = 6; + a.val7 = 7; + + assertEquals(0, a.val0); + assertEquals(1, a.val1); + assertEquals(2, a.val2); + assertEquals(3, a.val3); + assertEquals(4, a.val4); + assertEquals(5, a.val5); + assertEquals(6, a.val6); + assertEquals(7, a.val7); + assertEquals(0 + 1 + 2 + 3 + 4 + 5 + 6 + 7, a.sum()); + + __toVersion__(2); + + assertEquals(0, a.val0); + assertEquals(1, a.val1); + assertEquals(2, a.val2); + assertEquals(3, a.val3); + assertEquals(4, a.val4); + assertEquals(5, a.val5); + assertEquals(6, a.val6); + assertEquals(7, a.val7); + assertEquals(0 + 1 + 2 + 3 + 4 + 5 + 6 + 7, a.sum()); + + a.increaseAllByOne(); + assertEquals(0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 16, a.sum()); + + __toVersion__(0); + + assertEquals(0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8, a.sum()); + assertEquals(1, a.val0); + assertEquals(2, a.val1); + assertEquals(3, a.val2); + assertEquals(4, a.val3); + assertEquals(5, a.val4); + assertEquals(6, a.val5); + assertEquals(7, a.val6); + assertEquals(8, a.val7); + + __toVersion__(2); + + assertEquals(0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8, a.sum()); + assertEquals(1, a.val0); + assertEquals(2, a.val1); + assertEquals(3, a.val2); + assertEquals(4, a.val3); + assertEquals(5, a.val4); + assertEquals(6, a.val5); + assertEquals(7, a.val6); + assertEquals(8, a.val7); + + a.increaseAllByOne(); + + assertEquals(0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 16, a.sum()); + assertEquals(2, a.val0); + assertEquals(3, a.val1); + assertEquals(4, a.val2); + assertEquals(5, a.val3); + assertEquals(6, a.val4); + assertEquals(7, a.val5); + assertEquals(8, a.val6); + assertEquals(9, a.val7); + __toVersion__(0); + + assertEquals(0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 16, a.sum()); + assertEquals(2, a.val0); + assertEquals(3, a.val1); + assertEquals(4, a.val2); + assertEquals(5, a.val3); + assertEquals(6, a.val4); + assertEquals(7, a.val5); + assertEquals(8, a.val6); + assertEquals(9, a.val7); + } + + @Test + public void testAddRemoveField() { + + assert __version__() == 0; + + A a = new A(); + + assertEquals(0, a.val0); + assertEquals(0, a.val1); + + __toVersion__(1); + + a.val0 = 1234; + + __toVersion__(0); + + assertEquals(1234, a.val0); + assertEquals(0, a.val1); + + a.val1 = 1234; + + assertEquals(1234, a.val0); + assertEquals(1234, a.val1); + + __toVersion__(1); + + assertEquals(1234, a.val0); + + __toVersion__(0); + + assertEquals(1234, a.val0); + assertEquals(0, a.val1); + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/fields/FieldsTestSuite.java b/dcevm/src/test/java/org/dcevm/test/fields/FieldsTestSuite.java new file mode 100644 index 00000000..55ce5941 --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/fields/FieldsTestSuite.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.fields; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +/** + * Class redefinition tests that may change the methods and fields of class, but do not change the superklass or the implemented + * interface. + * + * @author Thomas Wuerthinger + */ +@RunWith(Suite.class) +@Suite.SuiteClasses({ + FieldChangedOrderTest.class, + FieldModificationTest.class, + ObjectStressTest.class, + YieldTest.class, + ComplexFieldTest.class, + FieldAlignmentTest.class, + StringFieldTest.class, + RedefinePrivateFieldTest.class, + EnumTest.class +}) +public class FieldsTestSuite { +} diff --git a/dcevm/src/test/java/org/dcevm/test/fields/ObjectStressTest.java b/dcevm/src/test/java/org/dcevm/test/fields/ObjectStressTest.java new file mode 100644 index 00000000..5109fb9b --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/fields/ObjectStressTest.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.fields; + +import org.junit.Before; +import org.junit.Test; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; +import static org.junit.Assert.assertEquals; + +/** + * @author Thomas Wuerthinger + */ +public class ObjectStressTest { + + private final int COUNT = 10000; + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + // Version 0 + public static class A { + + public A thisPointer; + public int i1; + public int i2; + public int i3; + public int i4; + public int i5; + public int i6; + public int i7; + public int i8; + public int i9; + public int i10; + + public int sum() { + return i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9 + i10; + } + } + + // Version 1 + public static class A___1 { + + public int i1; + public int i2; + public int i8; + public int i3; + public int i4; + public int i10; + public int i5; + public int i6; + public int i7; + public int i9; + public A thisPointer; + + public int sum() { + return i1 * i2 * i3 * i4 * i5 * i6 * i7 * i8 * i9 * i10; + } + } + + @Test + public void testLotsOfObjects() { + + assert __version__() == 0; + + A[] arr = new A[COUNT]; + for (int i = 0; i < arr.length; i++) { + arr[i] = new A(); + arr[i].thisPointer = arr[i]; + arr[i].i1 = 1; + arr[i].i2 = 2; + arr[i].i3 = 3; + arr[i].i4 = 4; + arr[i].i5 = 5; + arr[i].i6 = 6; + arr[i].i7 = 7; + arr[i].i8 = 8; + arr[i].i9 = 9; + arr[i].i10 = 10; + } + + + __toVersion__(1); + + for (int i = 0; i < arr.length; i++) { + assertEquals(1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10, arr[i].sum()); + assertEquals(arr[i].thisPointer, arr[i]); + } + + __toVersion__(0); + + for (int i = 0; i < arr.length; i++) { + assertEquals(1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10, arr[i].sum()); + assertEquals(arr[i].thisPointer, arr[i]); + } + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/fields/RedefinePrivateFieldTest.java b/dcevm/src/test/java/org/dcevm/test/fields/RedefinePrivateFieldTest.java new file mode 100644 index 00000000..c2ea1dea --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/fields/RedefinePrivateFieldTest.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.fields; + +import org.junit.Before; +import org.junit.Test; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; +import static org.junit.Assert.assertEquals; + +/** + * Tests redefinition of a class such that old code still accesses a redefined private field. + * + * @author Thomas Wuerthinger + */ +public class RedefinePrivateFieldTest { + + // Version 0 + public static class A { + + private int f1; + + public A() { + f1 = 5; + } + + public int foo() { + int result = f1; + __toVersion__(1); + result += f1; + return result; + } + } + + // Version 1 + public static class A___1 { + + int f0; + int f1; + + public int foo() { + return -1; + } + } + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + @Test + public void testRedefinePrivateField() { + + assert __version__() == 0; + + A a = new A(); + + assertEquals(10, a.foo()); + + assert __version__() == 1; + + assertEquals(-1, a.foo()); + + __toVersion__(0); + + assertEquals(10, a.foo()); + + assert __version__() == 1; + + assertEquals(-1, a.foo()); + + __toVersion__(0); + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/fields/StringFieldTest.java b/dcevm/src/test/java/org/dcevm/test/fields/StringFieldTest.java new file mode 100644 index 00000000..2bf7167a --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/fields/StringFieldTest.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.fields; + +import org.junit.Before; +import org.junit.Test; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; +import static org.junit.Assert.assertEquals; + +/** + * Complex field test. + * + * @author Thomas Wuerthinger + */ +public class StringFieldTest { + + // Version 0 + public static class A { + public String stringFld = "OLD"; + } + + // Version 1 + public static class A___1 { + public String stringFld = "NEW"; + public int intComplNewFld = 333; + public long longComplNewFld = 444L; + public String stringComplNewFld = "completely new String field"; + } + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + /** + * Checks that the given object is unmodified (i.e. the values of the fields are correct) + * + * @param a the object to be checked + */ + private void assertObjectOK(A a) { + assertEquals("OLD", a.stringFld); + } + + @Test + public void testComplexFieldChange() { + assert __version__() == 0; + A a = new A(); + assertObjectOK(a); + __toVersion__(1); + assertObjectOK(a); + __toVersion__(0); + assertObjectOK(a); + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/fields/YieldTest.java b/dcevm/src/test/java/org/dcevm/test/fields/YieldTest.java new file mode 100644 index 00000000..0f5dc40c --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/fields/YieldTest.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.fields; + +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; +import static org.junit.Assert.assertEquals; + +/** + * Test case that produces a list of integer values recursively. + * The recursive function does not contain a conditional statement. + * The recursion is stopped by swapping the recursive method with a different non-recursive implementation. + * + * @author Thomas Wuerthinger + */ +public class YieldTest { + + // Version 0 + public static class Base { + + protected List<Integer> arr = new ArrayList<Integer>(); + + public void reset() { + __toVersion__(0); + } + + public void next() { + __toVersion__(__version__() + 1); + } + } + + public static abstract class A extends Base { + + public List<Integer> gen() { + arr.add(produce()); + next(); + return gen(); + } + + public abstract int produce(); + } + + public static class B extends A { + + @Override + public int produce() { + return 1; + } + } + + public static class B___10 extends A { + + @Override + public int produce() { + return 2; + } + } + + public static class B___20 extends A { + + private int x; + + @Override + public int produce() { + return ++x; + } + } + + public static class A___30 extends Base { + + public List<Integer> gen() { + reset(); + return arr; + } + } + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + @Test + public void testYield() { + + assert __version__() == 0; + + B b = new B(); + assertEquals(Arrays.asList( + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10), b.gen()); + assert __version__() == 0; + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/methods/AddMethodTest.java b/dcevm/src/test/java/org/dcevm/test/methods/AddMethodTest.java new file mode 100644 index 00000000..7a56b577 --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/methods/AddMethodTest.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package org.dcevm.test.methods; + +import org.dcevm.test.TestUtil; +import org.junit.Before; +import org.junit.Test; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * Tests for adding / removing methods in a single class. + * + * @author Thomas Wuerthinger + */ +public class AddMethodTest { + + // 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); + } + + private void checkLineNumbers(int first, int second) { + assertTrue("Must have different line numbers (A.value is an EMCP method and therefore execution has to be transferred). Exception line numbers: " + first + " and " + second, first != second); + } + + @Test + public void testAddMethodToKlassWithEMCPExceptionMethod() { + + assert __version__() == 0; + + final A a = new A(); + + assertEquals(1, a.value(1)); + + __toVersion__(1); + + int firstLineNumber = TestUtil.assertException(IllegalArgumentException.class, new Runnable() { + @Override + public void run() { + assertEquals(4, a.value(1)); + } + }); + + int secondLineNumber = TestUtil.assertException(IllegalArgumentException.class, new Runnable() { + @Override + public void run() { + assertEquals(4, a.value(2)); + } + }); + + checkLineNumbers(firstLineNumber, secondLineNumber); + + assert __version__() == 2; + + int newFirstLineNumber = TestUtil.assertException(IllegalArgumentException.class, new Runnable() { + @Override + public void run() { + assertEquals(4, a.value(2)); + } + }); + + assertEquals(secondLineNumber, newFirstLineNumber); + + int newSecondLineNumber = TestUtil.assertException(IllegalArgumentException.class, new Runnable() { + @Override + public void run() { + assertEquals(4, a.value(1)); + } + }); + + assertEquals(newSecondLineNumber, firstLineNumber); + checkLineNumbers(firstLineNumber, secondLineNumber); + + __toVersion__(0); + assertEquals(1, a.value(1)); + assert __version__() == 0; + } +}
\ No newline at end of file diff --git a/dcevm/src/test/java/org/dcevm/test/methods/AnnotationTest.java b/dcevm/src/test/java/org/dcevm/test/methods/AnnotationTest.java new file mode 100644 index 00000000..bb25162f --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/methods/AnnotationTest.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package org.dcevm.test.methods; + +import org.junit.Before; +import org.junit.Test; + +import java.lang.annotation.*; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; +import static org.junit.Assert.assertEquals; + +/** + * Tests for adding / removing annotations on methods, fields and classes. + * + * @author Thomas Wuerthinger + * @author Jiri Bubnik + */ +public class AnnotationTest { + + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE}) + public @interface TestAnnotation { + } + + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE}) + public @interface TestAnnotation2 { + } + + + // Version 0 + public static class A { + public int testField; + + public void testMethod() { + } + } + + // Version 1 + @TestAnnotation + public static class A___1 { + @TestAnnotation + public int testField; + + @TestAnnotation + public void testMethod() { + } + } + + // Version 2 + @TestAnnotation2 + public static class A___2 { + @TestAnnotation2 + public int testField; + + @TestAnnotation2 + public void testMethod() { + } + } + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + private void checkAnnotation(Class<?> c, Class<? extends Annotation> expectedAnnotation) throws NoSuchMethodException, NoSuchFieldException { + Class<? extends Annotation> annotation = c.getAnnotation(expectedAnnotation).annotationType(); + assertEquals(expectedAnnotation, annotation); + Method m = c.getMethod("testMethod"); + annotation = m.getAnnotation(expectedAnnotation).annotationType(); + assertEquals(expectedAnnotation, annotation); + Field f = c.getField("testField"); + annotation = f.getAnnotation(expectedAnnotation).annotationType(); + assertEquals(expectedAnnotation, annotation); + } + + private void checkAnnotationMissing(Class<A> c) throws NoSuchMethodException, NoSuchFieldException { + assertEquals(0, c.getAnnotations().length); + assertEquals(0, c.getField("testField").getAnnotations().length); + assertEquals(0, c.getMethod("testMethod").getAnnotations().length); + } + + @Test + public void testAddMethodToKlassWithEMCPExceptionMethod() throws NoSuchMethodException, NoSuchFieldException { + + assert __version__() == 0; + checkAnnotationMissing(A.class); + __toVersion__(1); + checkAnnotation(A.class, TestAnnotation.class); + __toVersion__(2); + checkAnnotation(A.class, TestAnnotation2.class); + __toVersion__(0); + checkAnnotationMissing(A.class); + } + +}
\ No newline at end of file diff --git a/dcevm/src/test/java/org/dcevm/test/methods/ClassObjectHashcodeTest.java b/dcevm/src/test/java/org/dcevm/test/methods/ClassObjectHashcodeTest.java new file mode 100644 index 00000000..846c86e4 --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/methods/ClassObjectHashcodeTest.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package org.dcevm.test.methods; + +import org.junit.Before; +import org.junit.Test; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * Redefines a class and tests that the identity hashcode of the + * java.lang.Class object is retained. Also tests the combination of + * locking and retrieving the hashcode. + * + * @author Thomas Wuerthinger + */ +public class ClassObjectHashcodeTest { + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + // Version 0 + public static class A { + + public int value() { + return 1; + } + } + + // Version 1 + public static class A___1 { + + public int value() { + return 2; + } + } + + @Test + public void testClassObjectHashcode() { + A a = new A(); + Class clazz = a.getClass(); + int hashCode = clazz.hashCode(); + assertEquals(1, a.value()); + __toVersion__(1); + assertEquals(2, a.value()); + assertEquals(hashCode, clazz.hashCode()); + assertEquals(hashCode, a.getClass().hashCode()); + __toVersion__(0); + synchronized (clazz) { + assertEquals(1, a.value()); + assertEquals(hashCode, clazz.hashCode()); + assertEquals(hashCode, a.getClass().hashCode()); + __toVersion__(1); + assertEquals(2, a.value()); + assertTrue(a.getClass() == clazz); + assertTrue(a.getClass() == ClassObjectHashcodeTest.A.class); + assertEquals(hashCode, clazz.hashCode()); + assertEquals(hashCode, a.getClass().hashCode()); + } + assertEquals(2, a.value()); + assertTrue(a.getClass() == clazz); + __toVersion__(0); + assertTrue(a.getClass() == clazz); + assertEquals(hashCode, clazz.hashCode()); + assertEquals(hashCode, a.getClass().hashCode()); + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/methods/ClassObjectSynchronizationTest.java b/dcevm/src/test/java/org/dcevm/test/methods/ClassObjectSynchronizationTest.java new file mode 100644 index 00000000..8bf5eab5 --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/methods/ClassObjectSynchronizationTest.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package org.dcevm.test.methods; + +import org.junit.Before; +import org.junit.Test; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * Redefines a class and tests that the lock on the java.lang.Class object + * is retained. Also tests that the object identity of the java.lang.Class + * object is not changed. + * + * @author Thomas Wuerthinger + */ +public class ClassObjectSynchronizationTest { + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + // Version 0 + public static class A { + + public int value() { + return 1; + } + } + + // Version 1 + public static class A___1 { + + public int value() { + return 2; + } + } + + @Test + public void testClassObjectSynchronization() { + A a = new A(); + Class clazz = a.getClass(); + synchronized (clazz) { + assertEquals(1, a.value()); + __toVersion__(1); + assertEquals(2, a.value()); + assertTrue(a.getClass() == clazz); + assertTrue(a.getClass() == ClassObjectSynchronizationTest.A.class); + } + assertEquals(2, a.value()); + assertTrue(a.getClass() == clazz); + __toVersion__(0); + assertTrue(a.getClass() == clazz); + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/methods/ClassReflectionTest.java b/dcevm/src/test/java/org/dcevm/test/methods/ClassReflectionTest.java new file mode 100644 index 00000000..75fc38b4 --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/methods/ClassReflectionTest.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.methods; + +import junit.framework.Assert; +import org.dcevm.test.TestUtil; +import org.junit.Before; +import org.junit.Test; + +import java.lang.ref.SoftReference; +import java.lang.reflect.Method; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; +import static org.junit.Assert.assertEquals; + +/** + * Testing correct reflection functionality after class redefinition. + * + * @author Thomas Wuerthinger + */ +public class ClassReflectionTest { + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + // Version 0 + public static class A { + + public int value() { + return 1; + } + } + + public static class B extends A { + + @Override + public int value() { + return 2; + } + } + + public static class C extends A { + + @Override + public int value() { + return 3; + } + } + + // Version 1 + public static class A___1 { + + public int value() { + return 1; + } + + public int value2() { + return 2; + } + } + + // Version 2 + public static class C___2 extends B { + + @Override + public int value() { + return super.value(); + } + } + + private void assertIsSuper(Class<?> s, Class<?> c) { + assertEquals(s, c.getSuperclass()); + } + + private void assertIsNotSuper(Class<?> s, Class<?> c) { + Assert.assertFalse(s.equals(c.getSuperclass())); + } + + @Test + public void testClassReflection() { + + checkWeakReference(); + assert __version__() == 0; + + final A a = new A(); + final B b = new B(); + final C c = new C(); + + assertIsSuper(A.class, B.class); + assertIsSuper(A.class, C.class); + assertIsNotSuper(B.class, C.class); + + assertEquals(1, a.value()); + assertEquals(2, b.value()); + assertEquals(3, c.value()); + + __toVersion__(2); + + assertIsSuper(A.class, B.class); + assertIsSuper(B.class, C.class); + assertIsNotSuper(A.class, C.class); + + assertEquals(1, a.value()); + assertEquals(2, b.value()); + assertEquals(2, c.value()); + + TestUtil.assertUnsupportedWithLight(new Runnable() { + @Override + public void run() { + __toVersion__(0); + + assertIsSuper(A.class, B.class); + assertIsSuper(A.class, C.class); + assertIsNotSuper(B.class, C.class); + + assertEquals(1, a.value()); + assertEquals(2, b.value()); + assertEquals(3, c.value()); + } + }); + } + + public void checkWeakReference() { + A a = new A(); + Class<?> strongRef = a.getClass(); + SoftReference<Class<?>> softRef = new SoftReference<Class<?>>(a.getClass()); + + assertEquals(1, a.value()); + __toVersion__(1); + assertEquals(1, a.value()); + Assert.assertTrue(strongRef == softRef.get()); + + __toVersion__(0); + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/methods/DeleteActiveMethodTest.java b/dcevm/src/test/java/org/dcevm/test/methods/DeleteActiveMethodTest.java new file mode 100644 index 00000000..da957093 --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/methods/DeleteActiveMethodTest.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.methods; + +import junit.framework.Assert; +import org.dcevm.test.TestUtil; +import org.junit.Before; +import org.junit.Test; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; +import static org.junit.Assert.assertEquals; + +/** + * Test cases that delete a method that is currently active on the stack. + * + * @author Thomas Wuerthinger + */ +public class DeleteActiveMethodTest { + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + // Version 0 + public static class A { + + boolean firstCall; + + public int value() { + firstCall = true; + return helperValue(); + } + + public int helperValue() { + + if (!firstCall) { + return -1; + } + firstCall = false; + + Thread t = new Thread(new Runnable() { + + @Override + public void run() { + __toVersion__(1); + } + }); + t.start(); + + try { + do { + this.helperValue(); + } while (t.isAlive()); + this.helperValue(); + Assert.fail("Exception expected!"); + } catch (NoSuchMethodError e) { + } + + try { + t.join(); + } catch (InterruptedException e) { + } + + return 1; + } + } + + public static class B { + + public int fac(int x) { + if (x == 0) { + __toVersion__(1); + } + + return x * fac(x - 1); + } + } + + // Version 1 + public static class A___1 { + + boolean firstCall; + + public int value() { + __toVersion__(0); + return 2; + } + } + + public static class B___1 { + } + + @Test + public void testDeleteActiveMethodSimple() { + assert __version__() == 0; + + final B b = new B(); + TestUtil.assertException(NoSuchMethodError.class, new Runnable() { + @Override + public void run() { + b.fac(5); + } + }); + + assert __version__() == 1; + + __toVersion__(0); + assert __version__() == 0; + } + + @Test + public void testDeleteActiveMethod() { + assert __version__() == 0; + + A a = new A(); + + assertEquals(1, a.value()); + assert __version__() == 1; + + assertEquals(2, a.value()); + assert __version__() == 0; + + assertEquals(1, a.value()); + assert __version__() == 1; + + assertEquals(2, a.value()); + assert __version__() == 0; + + assertEquals(1, a.value()); + assert __version__() == 1; + + assertEquals(2, a.value()); + assert __version__() == 0; + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/methods/MethodReflectionTest.java b/dcevm/src/test/java/org/dcevm/test/methods/MethodReflectionTest.java new file mode 100644 index 00000000..7c1eaaf7 --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/methods/MethodReflectionTest.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.methods; + +import junit.framework.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.lang.reflect.Method; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; +import static org.junit.Assert.assertEquals; + +/** + * Testing correct reflection functionality after class redefinition. + * + * @author Thomas Wuerthinger + */ +public class MethodReflectionTest { + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + // Version 0 + public static class A { + + public int value() { + return 1; + } + } + + public static class B extends A { + + @Override + public int value() { + return 2; + } + } + + public static class C extends A { + + @Override + public int value() { + return 3; + } + } + + // Version 1 + public static class A___1 { + + public int value() { + return 1; + } + + public int value2() { + return 2; + } + } + + // Version 2 + public static class C___2 extends B { + + @Override + public int value() { + return super.value(); + } + } + + @Test + public void testMethodReflection() { + + assert __version__() == 0; + + A a = new A(); + B b = new B(); + C c = new C(); + + assertEquals(1, a.value()); + assertEquals(2, b.value()); + assertEquals(3, c.value()); + + assertContainsMethod(A.class, "value"); + assertDoesNotContainMethod(A.class, "value2"); + + __toVersion__(1); + + assertEquals(1, a.value()); + assertEquals(2, b.value()); + assertEquals(3, c.value()); + + assertContainsMethod(A.class, "value"); + assertContainsMethod(A.class, "value2"); + + __toVersion__(0); + + assertEquals(1, a.value()); + assertEquals(2, b.value()); + assertEquals(3, c.value()); + + assertContainsMethod(A.class, "value"); + assertDoesNotContainMethod(A.class, "value2"); + } + + private void assertContainsMethod(Class<?> c, String methodName) { + boolean found = false; + for (Method m : c.getDeclaredMethods()) { + if (m.getName().equals(methodName)) { + found = true; + break; + } + } + + Assert.assertTrue(found); + } + + private void assertDoesNotContainMethod(Class<?> c, String methodName) { + boolean found = false; + for (Method m : c.getDeclaredMethods()) { + if (m.getName().equals(methodName)) { + found = true; + break; + } + } + + Assert.assertFalse(found); + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/methods/MethodsTestSuite.java b/dcevm/src/test/java/org/dcevm/test/methods/MethodsTestSuite.java new file mode 100644 index 00000000..20888623 --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/methods/MethodsTestSuite.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.methods; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +/** + * Class redefinition tests that perform adding/removing/changing the methods of a class. + * + * @author Thomas Wuerthinger + */ +@RunWith(Suite.class) +@Suite.SuiteClasses({ + AddMethodTest.class, + DeleteActiveMethodTest.class, + ClassReflectionTest.class, + MethodReflectionTest.class, + ClassObjectSynchronizationTest.class, + ClassObjectHashcodeTest.class, + OverrideMethodTest.class, + SingleClassTest.class, + SingleClassReflectionTest.class, + AnnotationTest.class +}) +public class MethodsTestSuite { +} diff --git a/dcevm/src/test/java/org/dcevm/test/methods/OverrideMethodTest.java b/dcevm/src/test/java/org/dcevm/test/methods/OverrideMethodTest.java new file mode 100644 index 00000000..dc98d608 --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/methods/OverrideMethodTest.java @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.methods; + +import org.junit.Before; +import org.junit.Test; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; +import static org.junit.Assert.assertEquals; + +/** + * Tests for the class relationship A<B<C with adding / removing methods. + * + * @author Thomas Wuerthinger + */ +public class OverrideMethodTest { + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + // Version 0 + public static class A { + + public int value() { + return 5; + } + } + + public static class B extends A { + + public int doubled() { + return value() * 2; + } + } + + public static class C extends B { + } + + // Version 1 + public static class A___1 { + + public int value() { + return 10; + } + } + + // Version 2 + public static class B___2 extends A { + + public int doubled() { + return value() * 3; + } + } + + // Version 3 + public static class C___3 extends B { + + @Override + public int value() { + return 1; + } + } + + // Verison 4 + public static class A___4 { + + public int value() { + return baseValue(); + } + + public int baseValue() { + return 20; + } + } + + public static class B___4 extends A { + + public int doubled() { + return value() * 2; + } + } + + public static class C___4 extends B { + } + + // Verison 5 + public static class A___5 { + + public int value() { + return baseValue(); + } + + public int baseValue() { + return 20; + } + } + + @Test + public void testSimple() { + + assert __version__() == 0; + + A a = new A(); + B b = new B(); + C c = new C(); + + assertEquals(5, a.value()); + assertEquals(5, b.value()); + assertEquals(10, b.doubled()); + assertEquals(5, c.value()); + assertEquals(10, c.doubled()); + + __toVersion__(1); + assertEquals(10, a.value()); + assertEquals(10, b.value()); + assertEquals(20, b.doubled()); + assertEquals(10, c.value()); + assertEquals(20, c.doubled()); + + __toVersion__(2); + assertEquals(10, a.value()); + assertEquals(10, b.value()); + assertEquals(30, b.doubled()); + assertEquals(10, c.value()); + assertEquals(30, c.doubled()); + + __toVersion__(0); + assertEquals(5, a.value()); + assertEquals(5, b.value()); + assertEquals(10, b.doubled()); + assertEquals(5, c.value()); + assertEquals(10, c.doubled()); + } + + @Test + public void testMethodAdd() { + + assert __version__() == 0; + A a = new A(); + B b = new B(); + C c = new C(); + + assertEquals(5, a.value()); + assertEquals(5, b.value()); + assertEquals(10, b.doubled()); + assertEquals(5, c.value()); + assertEquals(10, c.doubled()); + + __toVersion__(4); + assertEquals(20, a.value()); + assertEquals(40, b.doubled()); + assertEquals(20, b.value()); + assertEquals(20, c.value()); + assertEquals(40, c.doubled()); + + __toVersion__(0); + assertEquals(5, a.value()); + assertEquals(5, b.value()); + assertEquals(10, b.doubled()); + assertEquals(5, c.value()); + assertEquals(10, c.doubled()); + } + + @Test + public void testOverride() { + + assert __version__() == 0; + + A a = new A(); + B b = new B(); + C c = new C(); + + assertEquals(5, a.value()); + assertEquals(5, b.value()); + assertEquals(10, b.doubled()); + assertEquals(5, c.value()); + assertEquals(10, c.doubled()); + + __toVersion__(3); + assertEquals(5, a.value()); + assertEquals(5, b.value()); + assertEquals(10, b.doubled()); + assertEquals(1, c.value()); + assertEquals(2, c.doubled()); + + __toVersion__(0); + assertEquals(5, a.value()); + assertEquals(5, b.value()); + assertEquals(10, b.doubled()); + assertEquals(5, c.value()); + assertEquals(10, c.doubled()); + } + + @Test + public void testMethodAddAdvanced() { + + assert __version__() == 0; + A a = new A(); + B b = new B(); + C c = new C(); + + assertEquals(5, a.value()); + assertEquals(5, b.value()); + assertEquals(10, b.doubled()); + assertEquals(5, c.value()); + assertEquals(10, c.doubled()); + + __toVersion__(5); + assertEquals(20, a.value()); + assertEquals(20, b.value()); + assertEquals(40, b.doubled()); + assertEquals(20, c.value()); + assertEquals(40, c.doubled()); + + __toVersion__(0); + assertEquals(5, a.value()); + assertEquals(5, b.value()); + assertEquals(10, b.doubled()); + assertEquals(5, c.value()); + assertEquals(10, c.doubled()); + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/methods/SingleClassReflectionTest.java b/dcevm/src/test/java/org/dcevm/test/methods/SingleClassReflectionTest.java new file mode 100644 index 00000000..61d3d31a --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/methods/SingleClassReflectionTest.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.methods; + +import org.junit.Before; +import org.junit.Test; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; +import static org.junit.Assert.assertEquals; + +/** + * Testing correct behaviour of the class object after class redefinition (with respect to the identity hash code and synchronization). + * + * @author Thomas Wuerthinger + */ +public class SingleClassReflectionTest { + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + // Version 0 + public static class A { + + public static synchronized void staticSynchronized() { + __toVersion__(1); + } + } + + + // Version 1 + public static class A___1 { + public static synchronized void staticSynchronized() { + } + } + + + @Test + public void testHashcode() { + + assert __version__() == 0; + + A a = new A(); + + int hashcode = a.getClass().hashCode(); + + __toVersion__(1); + + assertEquals(hashcode, a.getClass().hashCode()); + + __toVersion__(0); + } + + @Test + public void testStaticSynchronized() { + + A.staticSynchronized(); + + assertEquals(1, __version__()); + + __toVersion__(0); + } + +} diff --git a/dcevm/src/test/java/org/dcevm/test/methods/SingleClassTest.java b/dcevm/src/test/java/org/dcevm/test/methods/SingleClassTest.java new file mode 100644 index 00000000..4e12bc26 --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/methods/SingleClassTest.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.methods; + +import org.junit.Before; +import org.junit.Test; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; +import static org.junit.Assert.assertEquals; + +/** + * Tests for adding / removing methods in a single class. + * + * @author Thomas Wuerthinger + */ +public class SingleClassTest { + + // Version 0 + public static class A { + + public int value() { + return 5; + } + } + + // Version 3 + public static class A___3 { + + public int value() { + return 5; + } + } + + // Version 1 + public static class A___1 { + + public int value() { + return 6; + } + + public int testValue() { + return 1; + + } + } + + // Version 2 + public static class A___2 { + + public int value() { + return baseValue() * 2; + } + + public int baseValue() { + return 10; + } + } + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + @Test + public void testSimpleReplacement() { + + assert __version__() == 0; + + A a = new A(); + + assertEquals(5, a.value()); + + __toVersion__(1); + + assertEquals(6, a.value()); + + __toVersion__(3); + + assertEquals(5, a.value()); + + __toVersion__(0); + + assertEquals(5, a.value()); + } + + @Test + public void testAddMethod() { + + assert __version__() == 0; + + A a = new A(); + assertEquals(a.value(), 5); + + __toVersion__(2); + assertEquals(a.value(), 20); + + __toVersion__(0); + assertEquals(a.value(), 5); + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/structural/AnonymousClassInMethodTest.java b/dcevm/src/test/java/org/dcevm/test/structural/AnonymousClassInMethodTest.java new file mode 100644 index 00000000..5f923110 --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/structural/AnonymousClassInMethodTest.java @@ -0,0 +1,67 @@ +package org.dcevm.test.structural; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; + +/** + * Test insertion and swap of anonymous classes. + */ +public class AnonymousClassInMethodTest { + + public static interface I { + public boolean m(); + }; + + public static interface I2 {}; + + // Version 0 + public static class A { + public boolean test() { + I anonymous = new I() { + @Override + public boolean m() { + return true; + } + }; + return anonymous.m(); + } + } + + // Version 1 + public static class A___1 { + public boolean test() { + I2 insertedAnonymous = new I2() {}; + + I anonymous = new I() { + @Override + public boolean m() { + return false; + } + }; + return anonymous.m(); + } + } + + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + // TODO this test fails, because conent of A$1 is now interface I2 instead of interface I (not compatible change) + // HotswapAgent plugin AnonymousClassPatch solves this on Java instrumentation level by exchanging content of class files. + // @see https://github.com/HotswapProjects/HotswapAgent/tree/master/HotswapAgent/src/main/java/org/hotswap/agent/plugin/jvm + //@Test + public void testAnonymous() { + assert __version__() == 0; + Assert.assertTrue(new A().test()); + __toVersion__(1); + Assert.assertFalse(new A().test()); + __toVersion__(0); + Assert.assertTrue(new A().test()); + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/structural/InterfaceTest.java b/dcevm/src/test/java/org/dcevm/test/structural/InterfaceTest.java new file mode 100644 index 00000000..1a089965 --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/structural/InterfaceTest.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.structural; + +import org.dcevm.test.TestUtil; +import org.junit.*; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; +import static org.junit.Assert.*; + +/** + * Tests for adding an interface to a class and for changing the methods of an interface. + * + * @author Thomas Wuerthinger + */ +public class InterfaceTest { + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + @After + public void tearDown() throws Exception { + } + + public static interface A { + + int giveMeFive(); + } + + public static class AImpl { + + public int giveMeFive() { + return 5; + } + } + + public static class BImpl implements A { + + @Override + public int giveMeFive() { + return 5; + } + + public int giveMeTen() { + return 10; + } + } + + public static class AImpl___1 implements A { + + @Override + public int giveMeFive() { + return 5; + } + } + + public static interface A___2 { + + int giveMeTen(); + } + + public static class Helper { + + public int giveMeTenA2(A a) { + return 3; + } + } + + public static class Helper___2 { + + public int giveMeTenA2(A a) { + return ((A___2) a).giveMeTen(); + } + } + + @Test + public void testAddInterface() { + + modifyInterface(); + assert __version__() == 0; + + AImpl a = new AImpl(); + assertFalse(a instanceof A); + try { + int val = (((A) a).giveMeFive()); + fail(); + } catch (ClassCastException e) { + } + + __toVersion__(1); + assertTrue(a instanceof A); + assertEquals(5, ((A) a).giveMeFive()); + + TestUtil.assertUnsupportedToVersionWithLight(InterfaceTest.class, 0); + } + + public void modifyInterface() { + + assert __version__() == 0; + + BImpl b = new BImpl(); + assertTrue(b instanceof A); + + __toVersion__(2); + + assertEquals(10, new Helper().giveMeTenA2(b)); + + __toVersion__(0); + assertEquals(5, ((A) b).giveMeFive()); + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/structural/RedefineClassClassTest.java b/dcevm/src/test/java/org/dcevm/test/structural/RedefineClassClassTest.java new file mode 100644 index 00000000..e0da9002 --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/structural/RedefineClassClassTest.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package org.dcevm.test.structural; + +import org.dcevm.ClassRedefinitionPolicy; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; + +/** + * Smallest test case for redefining the interface java/lang/reflect/Type (causes java/lang/Class being redefined) + * + * @author Thomas Wuerthinger + */ +@Ignore +public class RedefineClassClassTest { + + // Version 0 + public interface Type { + } + + // Version 1 + @ClassRedefinitionPolicy(alias = java.lang.reflect.Type.class) + public interface Type___1 { + } + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + @Test + public void testRedefineClass() { + + assert __version__() == 0; + + __toVersion__(1); + + __toVersion__(0); + + __toVersion__(1); + + __toVersion__(0); + + + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/structural/RedefineObjectClassTest.java b/dcevm/src/test/java/org/dcevm/test/structural/RedefineObjectClassTest.java new file mode 100644 index 00000000..08d07c1a --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/structural/RedefineObjectClassTest.java @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package org.dcevm.test.structural; + +import org.dcevm.ClassRedefinitionPolicy; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; +import static org.junit.Assert.assertEquals; + +/** + * Smallest test case for redefining java/lang/Object, without changing the number of virtual methods. + * + * @author Thomas Wuerthinger + */ +@Ignore +public class RedefineObjectClassTest { + + // Version 0 + public static class Helper { + public static String access(Object o) { + return ""; + } + } + + // Version 1 + + public static class Helper___1 { + public static String access(Object o) { + return ((A___1) o).myTestFunction___(); + } + } + + @ClassRedefinitionPolicy(alias = java.lang.Object.class) + public static class A___1 { + + public final native Class<? extends Object> getClass___(); + + @Override + public native int hashCode(); + + @Override + public boolean equals(Object obj) { + return (this == obj); + } + + public static int x; + public static int x1; + public static int x2; + public static int x3; + public static int x4; + public static int x5; + + @Override + protected native Object clone() throws CloneNotSupportedException; + + @Override + public String toString() { + System.out.println("x=" + (x++)); + return getClass().getName() + "@" + Integer.toHexString(hashCode());// myTestFunction___(); + } + + public final String myTestFunction___() { + return "org/dcevm/test"; + } + + public final native void notify___(); + + public final native void notifyAll___(); + + public final native void wait___(long timeout) throws InterruptedException; + + public final void wait___(long timeout, int nanos) throws InterruptedException { + + + if (timeout < 0) { + throw new IllegalArgumentException("timeout value is negative"); + } + + if (nanos < 0 || nanos > 999999) { + throw new IllegalArgumentException( + "nanosecond timeout value out of range"); + } + + if (nanos >= 500000 || (nanos != 0 && timeout == 0)) { + timeout++; + } + + wait(timeout); + } + + public final void wait___() throws InterruptedException { + wait(0); + } + + @Override + protected void finalize() throws Throwable { + } + } + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + @Test + public void testRedefineObject() { + + assert __version__() == 0; + + Object o = new Object(); + __toVersion__(1); + + System.out.println(this.toString()); + System.out.println(o.toString()); + System.out.println(this.toString()); + + + //assertEquals("test", o.toString()); + assertEquals("org/dcevm/test", Helper.access(o)); + __toVersion__(0); + __toVersion__(1); + __toVersion__(0); + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/structural/StructuralTestSuite.java b/dcevm/src/test/java/org/dcevm/test/structural/StructuralTestSuite.java new file mode 100644 index 00000000..633ba059 --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/structural/StructuralTestSuite.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.structural; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +/** + * Class redefinition tests that do arbitrary structural changes. + * <p/> + * TODO: Add a test where redefinition triggers classloading (e.g. because a super type is not yet loaded). + * + * @author Thomas Wuerthinger + */ +@RunWith(Suite.class) +@Suite.SuiteClasses({ + RedefineClassClassTest.class, + RedefineObjectClassTest.class, + InterfaceTest.class, + ThisTypeChange.class +}) +public class StructuralTestSuite { +} diff --git a/dcevm/src/test/java/org/dcevm/test/structural/ThisTypeChange.java b/dcevm/src/test/java/org/dcevm/test/structural/ThisTypeChange.java new file mode 100644 index 00000000..9cfde217 --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/structural/ThisTypeChange.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.structural; + +import org.dcevm.test.TestUtil; +import org.junit.Before; +import org.junit.Test; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; + +/** + * Tests that change the type of the object references by the Java this pointer. + * + * @author Thomas Wuerthinger + */ +public class ThisTypeChange { + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + // Version 0 + public static class A { + + public int valueOK() { + return 1; + } + + public int value() { + __toVersion__(1); + return 1; + } + } + + public static class B extends A { + + @Override + public int value() { + return super.value(); + } + + + @Override + public int valueOK() { + __toVersion__(1); + return super.valueOK(); + } + } + + // Version 1 + public static class A___1 { + + public int valueOK() { + return 2; + } + } + + // Version 1 + public static class B___1 { + } + + // Method to enforce cast (otherwise bytecodes become invalid in version 2) + public static A convertBtoA(Object b) { + return (A) b; + } + + @Test + public void testThisTypeChange() { + + assert __version__() == 0; + + final B b = new B(); + TestUtil.assertUnsupported(new Runnable() { + @Override + public void run() { + b.value(); + } + }); + + assert __version__() == 0; + + TestUtil.assertUnsupported(new Runnable() { + @Override + public void run() { + b.valueOK(); + } + }); + + assert __version__() == 0; + + TestUtil.assertUnsupported(new Runnable() { + @Override + public void run() { + b.valueOK(); + } + }); + + assert __version__() == 0; + } +} diff --git a/dcevm/src/test/java/org/dcevm/test/util/HotSwapTestHelper.java b/dcevm/src/test/java/org/dcevm/test/util/HotSwapTestHelper.java new file mode 100644 index 00000000..5ecbd83e --- /dev/null +++ b/dcevm/src/test/java/org/dcevm/test/util/HotSwapTestHelper.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package org.dcevm.test.util; + +import org.dcevm.HotSwapTool; + +/** + * Shortcut methods for testing. Methods are named this way to make them more visible in the test code. + * @author Ivan Dubrov + */ +public class HotSwapTestHelper { + /** + * Returns the current version of the inner classes of an outer class. + * <p/> + * Caller class is used as an outer class. + * + * @return the version of the inner classes of the outer class + */ + public static int __version__() { + return HotSwapTool.getCurrentVersion(determineOuter(0)); + } + + /** + * Redefines all inner classes of a outer class to a specified version. Inner classes who do not have a particular + * representation for a version remain unchanged. + * <p/> + * Caller class is used as an outer class. + * + * @param versionNumber the target version number + */ + public static void __toVersion__(int versionNumber) { + HotSwapTool.toVersion(determineOuter(0), versionNumber); + } + + /** + * Helper method to determine caller outer class. + * <p/> + * Takes caller class and finds its top enclosing class (which is supposed to be test class). + * + * @param level on which level this call is being made. 0 - call is made immediately in the method of HotSwapTool. + * @return outer class reference + */ + private static Class<?> determineOuter(int level) { + StackTraceElement[] stack = Thread.currentThread().getStackTrace(); + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + // one for Thread#getStackTrace + // one for #determineOuter + // one for the caller + String callerName = stack[level + 3].getClassName(); + try { + Class<?> clazz = cl.loadClass(callerName); + while (clazz.getEnclosingClass() != null) { + clazz = clazz.getEnclosingClass(); + } + return clazz; + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException("Cannot find caller class: " + callerName, e); + } + } +} diff --git a/dcevm/src/test/java8/org/dcevm/test/methods/DefaultMethodsTest.java b/dcevm/src/test/java8/org/dcevm/test/methods/DefaultMethodsTest.java new file mode 100644 index 00000000..de6b3c64 --- /dev/null +++ b/dcevm/src/test/java8/org/dcevm/test/methods/DefaultMethodsTest.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.dcevm.test.methods; + +import org.junit.Before; +import org.junit.Test; + +import static org.dcevm.test.util.HotSwapTestHelper.__toVersion__; +import static org.dcevm.test.util.HotSwapTestHelper.__version__; +import static org.junit.Assert.assertEquals; + +/** + * Tests for the class relationship A<B<C with adding / removing methods. + * + * @author Thomas Wuerthinger + */ +public class DefaultMethodsTest { + + @Before + public void setUp() throws Exception { + __toVersion__(0); + } + + // Version 0 + public static interface A { + default int value() { + __toVersion__(1); + return 1 + value(); + } + } + + public static class B implements A { + } + + public static interface C { + int value(); + } + + public static class D implements C { + @Override + public int value() { + __toVersion__(2); + return 3 + value(); + } + } + + // Version 1 + public static interface A___1 { + int value(); + } + + + public static class B___1 implements A { + public int value() { + return 2; + } + } + + // Version 2 + public static interface C___2 { + default int value() { + return 5; + } + } + + public static class D___2 implements C___2 { + } + + @Test + public void testDefaultMethodReplacedWithInstance() { + assert __version__() == 0; + + A a = new B(); + assertEquals(3, a.value()); + + __toVersion__(0); + } + + @Test + public void testInstanceMethodReplacedWithDefault() { + assert __version__() == 0; + + C c = new D(); + assertEquals(8, c.value()); + + __toVersion__(0); + } +} diff --git a/dcevm/src/test/java8/org/dcevm/test/util/HotSwapTestHelper.java b/dcevm/src/test/java8/org/dcevm/test/util/HotSwapTestHelper.java new file mode 100644 index 00000000..5ecbd83e --- /dev/null +++ b/dcevm/src/test/java8/org/dcevm/test/util/HotSwapTestHelper.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package org.dcevm.test.util; + +import org.dcevm.HotSwapTool; + +/** + * Shortcut methods for testing. Methods are named this way to make them more visible in the test code. + * @author Ivan Dubrov + */ +public class HotSwapTestHelper { + /** + * Returns the current version of the inner classes of an outer class. + * <p/> + * Caller class is used as an outer class. + * + * @return the version of the inner classes of the outer class + */ + public static int __version__() { + return HotSwapTool.getCurrentVersion(determineOuter(0)); + } + + /** + * Redefines all inner classes of a outer class to a specified version. Inner classes who do not have a particular + * representation for a version remain unchanged. + * <p/> + * Caller class is used as an outer class. + * + * @param versionNumber the target version number + */ + public static void __toVersion__(int versionNumber) { + HotSwapTool.toVersion(determineOuter(0), versionNumber); + } + + /** + * Helper method to determine caller outer class. + * <p/> + * Takes caller class and finds its top enclosing class (which is supposed to be test class). + * + * @param level on which level this call is being made. 0 - call is made immediately in the method of HotSwapTool. + * @return outer class reference + */ + private static Class<?> determineOuter(int level) { + StackTraceElement[] stack = Thread.currentThread().getStackTrace(); + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + // one for Thread#getStackTrace + // one for #determineOuter + // one for the caller + String callerName = stack[level + 3].getClassName(); + try { + Class<?> clazz = cl.loadClass(callerName); + while (clazz.getEnclosingClass() != null) { + clazz = clazz.getEnclosingClass(); + } + return clazz; + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException("Cannot find caller class: " + callerName, e); + } + } +} |