# HG changeset patch # User asaha # Date 1443477701 25200 # Node ID 4bbf0e9196f2786e0bc4f17664e2533808d944bf # Parent 3d13e757229cbe47bff2d2118642b9e9231ee2ee# Parent e48e953c86e8f9610098deff6854b7384956c58e Merge diff -r e48e953c86e8 -r 4bbf0e9196f2 .hgtags --- a/.hgtags Mon Sep 28 14:53:13 2015 -0700 +++ b/.hgtags Mon Sep 28 15:01:41 2015 -0700 @@ -713,6 +713,7 @@ e0d75c284bd1c09fd7d9ef09627d8a99b88d468d jdk8u60-b21 ff8fdeb2fb6d6f3348597339c53412f8f6202c3f hs25.60-b22 878cb0df27c22c6b1e9f4add1eb3da3edc8ab51d jdk8u60-b22 +ad04e0ef0f85625b68ed18e949c75399b8d9b99b hs25.66-b01 0e4094950cd312c8f95c7f37336606323fe049fe jdk8u60-b23 d89ceecf1bad55e1aee2932b8895d60fc64c15db hs25.60-b23 fb157d537278cda4150740e27bb57cd8694e15bf jdk8u60-b24 @@ -738,3 +739,17 @@ ccc03258fbcfbcdf515ceb87bd3699c8f849dc0d jdk8u65-b14 03ca585abe68e4dcce5bc162a0fa0593eb8fa2ee jdk8u65-b15 b4137dc9b1a83409fbd2b80d2ffd5ae949cd7a6b jdk8u65-b16 +878cb0df27c22c6b1e9f4add1eb3da3edc8ab51d jdk8u66-b00 +777a354cada52b831a32bfc5362ad7cedfde4450 jdk8u66-b01 +0366ad2644f58ec88af9cb2ea8c23a02559fb2d1 hs25.66-b02 +47110b037994f9006c22abcb12569fcafad84edb hs25.66-b03 +ae5624088d86abe8e7981dbb893c1b6da5140a1c jdk8u66-b02 +6594411c4eb4d00e439330a61744f077d0b96363 jdk8u66-b07 +aedefb75358f3cda5181bf594c2cda833056b25a jdk8u66-b08 +83621deea0fcb4a517b94c5546b4f8738588cb6c jdk8u66-b09 +5280a8174aea13bd242480419e6228857dac7b59 jdk8u66-b10 +8a23b6392c590b7bf5f6ad2c4746dc03981a7f60 jdk8u66-b11 +ab64d7ea4f48ea4bdbcc43d4a653be157d9c29e3 jdk8u66-b12 +4d699853544cf869d4edaf23b7cc9cfbb2900a2b jdk8u66-b13 +9f7f29ff487ae023ca1f697445004a532751b0d2 jdk8u66-b14 +5b67af3317bce1f940c5dc1535411a1002bed6c1 jdk8u66-b15 diff -r e48e953c86e8 -r 4bbf0e9196f2 make/defs.make --- a/make/defs.make Mon Sep 28 14:53:13 2015 -0700 +++ b/make/defs.make Mon Sep 28 15:01:41 2015 -0700 @@ -116,6 +116,18 @@ # hotspot version definitions include $(GAMMADIR)/make/hotspot_version +# When config parameter --with-update-version is defined, +# Hotspot minor version should be set to that +ifneq ($(JDK_UPDATE_VERSION),) + HS_MINOR_VER=$(JDK_UPDATE_VERSION) +endif + +# When config parameter --with-build-number is defined, +# Hotspot build number should be set to that +ifneq ($(JDK_BUILD_NUMBER),) + HS_BUILD_NUMBER=$(subst b,,$(JDK_BUILD_NUMBER)) +endif + # Java versions needed ifeq ($(PREVIOUS_JDK_VERSION),) PREVIOUS_JDK_VERSION=$(JDK_PREVIOUS_VERSION) diff -r e48e953c86e8 -r 4bbf0e9196f2 make/hotspot_version --- a/make/hotspot_version Mon Sep 28 14:53:13 2015 -0700 +++ b/make/hotspot_version Mon Sep 28 15:01:41 2015 -0700 @@ -34,8 +34,8 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2015 HS_MAJOR_VER=25 -HS_MINOR_VER=65 -HS_BUILD_NUMBER=01 +HS_MINOR_VER=66 +HS_BUILD_NUMBER=00 JDK_MAJOR_VER=1 JDK_MINOR_VER=8 diff -r e48e953c86e8 -r 4bbf0e9196f2 src/os/bsd/vm/jsig.c --- a/src/os/bsd/vm/jsig.c Mon Sep 28 14:53:13 2015 -0700 +++ b/src/os/bsd/vm/jsig.c Mon Sep 28 15:01:41 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, 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 @@ -36,6 +36,7 @@ #include #include #include +#include #define MAXSIGNUM 32 #define MASK(sig) ((unsigned int)1 << sig) @@ -43,6 +44,9 @@ static struct sigaction sact[MAXSIGNUM]; /* saved signal handlers */ static unsigned int jvmsigs = 0; /* signals used by jvm */ +static pthread_key_t reentry_flag_key; +static pthread_once_t reentry_key_init_once = PTHREAD_ONCE_INIT; + /* used to synchronize the installation of signal handlers */ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; @@ -59,6 +63,15 @@ static bool jvm_signal_installing = false; static bool jvm_signal_installed = false; +#define check_status(cmd) \ + do { \ + int status = (cmd); \ + if (status != 0) { \ + printf("error %s (%d) in " #cmd "\n", strerror(status), status); \ + exit(1); \ + } \ + } while (0) + static void signal_lock() { pthread_mutex_lock(&mutex); /* When the jvm is installing its set of signal handlers, threads @@ -74,8 +87,15 @@ pthread_mutex_unlock(&mutex); } +static void reentry_tls_init() { + // value for reentry_flag_key will default to NULL (false) + check_status(pthread_key_create(&reentry_flag_key, NULL)); +} + static sa_handler_t call_os_signal(int sig, sa_handler_t disp, bool is_sigset) { + sa_handler_t res; + if (os_signal == NULL) { if (!is_sigset) { os_signal = (signal_t)dlsym(RTLD_NEXT, "signal"); @@ -87,7 +107,12 @@ exit(0); } } - return (*os_signal)(sig, disp); + check_status(pthread_once(&reentry_key_init_once, reentry_tls_init)); + // set reentry_flag_key to non-NULL to show reentry + check_status(pthread_setspecific(reentry_flag_key, &res)); + res = (*os_signal)(sig, disp); + check_status(pthread_setspecific(reentry_flag_key, NULL)); + return res; } static void save_signal_handler(int sig, sa_handler_t disp) { @@ -161,6 +186,11 @@ bool sigused; struct sigaction oldAct; + check_status(pthread_once(&reentry_key_init_once, reentry_tls_init)); + if (pthread_getspecific(reentry_flag_key) != NULL) { + return call_os_sigaction(sig, act, oact); + } + signal_lock(); sigused = (MASK(sig) & jvmsigs) != 0; diff -r e48e953c86e8 -r 4bbf0e9196f2 src/share/vm/classfile/classFileParser.cpp --- a/src/share/vm/classfile/classFileParser.cpp Mon Sep 28 14:53:13 2015 -0700 +++ b/src/share/vm/classfile/classFileParser.cpp Mon Sep 28 15:01:41 2015 -0700 @@ -4421,9 +4421,15 @@ Method* m = k->lookup_method(vmSymbols::finalize_method_name(), vmSymbols::void_method_signature()); if (m != NULL && !m->is_empty_method()) { - f = true; + f = true; } - assert(f == k->has_finalizer(), "inconsistent has_finalizer"); + + // Spec doesn't prevent agent from redefinition of empty finalizer. + // Despite the fact that it's generally bad idea and redefined finalizer + // will not work as expected we shouldn't abort vm in this case + if (!k->has_redefined_this_or_super()) { + assert(f == k->has_finalizer(), "inconsistent has_finalizer"); + } #endif // Check if this klass supports the java.lang.Cloneable interface diff -r e48e953c86e8 -r 4bbf0e9196f2 src/share/vm/classfile/javaClasses.cpp --- a/src/share/vm/classfile/javaClasses.cpp Mon Sep 28 14:53:13 2015 -0700 +++ b/src/share/vm/classfile/javaClasses.cpp Mon Sep 28 15:01:41 2015 -0700 @@ -782,6 +782,22 @@ return name; } +// Returns the Java name for this Java mirror (Resource allocated) +// See Klass::external_name(). +// For primitive type Java mirrors, its type name is returned. +const char* java_lang_Class::as_external_name(oop java_class) { + assert(java_lang_Class::is_instance(java_class), "must be a Class object"); + const char* name = NULL; + if (is_primitive(java_class)) { + name = type2name(primitive_type(java_class)); + } else { + name = as_Klass(java_class)->external_name(); + } + if (name == NULL) { + name = ""; + } + return name; +} Klass* java_lang_Class::array_klass(oop java_class) { Klass* k = ((Klass*)java_class->metadata_field(_array_klass_offset)); diff -r e48e953c86e8 -r 4bbf0e9196f2 src/share/vm/classfile/javaClasses.hpp --- a/src/share/vm/classfile/javaClasses.hpp Mon Sep 28 14:53:13 2015 -0700 +++ b/src/share/vm/classfile/javaClasses.hpp Mon Sep 28 15:01:41 2015 -0700 @@ -270,6 +270,7 @@ } static Symbol* as_signature(oop java_class, bool intern_if_not_found, TRAPS); static void print_signature(oop java_class, outputStream *st); + static const char* as_external_name(oop java_class); // Testing static bool is_instance(oop obj) { return obj != NULL && obj->klass() == SystemDictionary::Class_klass(); diff -r e48e953c86e8 -r 4bbf0e9196f2 src/share/vm/oops/instanceKlass.cpp --- a/src/share/vm/oops/instanceKlass.cpp Mon Sep 28 14:53:13 2015 -0700 +++ b/src/share/vm/oops/instanceKlass.cpp Mon Sep 28 15:01:41 2015 -0700 @@ -439,6 +439,9 @@ if (!constants()->is_shared()) { MetadataFactory::free_metadata(loader_data, constants()); } + // Delete any cached resolution errors for the constant pool + SystemDictionary::delete_resolution_error(constants()); + set_constants(NULL); } @@ -1569,6 +1572,21 @@ return NULL; } +#ifdef ASSERT +// search through class hierarchy and return true if this class or +// one of the superclasses was redefined +bool InstanceKlass::has_redefined_this_or_super() const { + const InstanceKlass* klass = this; + while (klass != NULL) { + if (klass->has_been_redefined()) { + return true; + } + klass = InstanceKlass::cast(klass->super()); + } + return false; +} +#endif + // lookup a method in the default methods list then in all transitive interfaces // Do NOT return private or static methods Method* InstanceKlass::lookup_method_in_ordered_interfaces(Symbol* name, diff -r e48e953c86e8 -r 4bbf0e9196f2 src/share/vm/oops/instanceKlass.hpp --- a/src/share/vm/oops/instanceKlass.hpp Mon Sep 28 14:53:13 2015 -0700 +++ b/src/share/vm/oops/instanceKlass.hpp Mon Sep 28 15:01:41 2015 -0700 @@ -808,6 +808,11 @@ bool implements_interface(Klass* k) const; bool is_same_or_direct_interface(Klass* k) const; +#ifdef ASSERT + // check whether this class or one of its superclasses was redefined + bool has_redefined_this_or_super() const; +#endif + // Access to the implementor of an interface. Klass* implementor() const { @@ -865,8 +870,8 @@ // Casting from Klass* static InstanceKlass* cast(Klass* k) { - assert(k->is_klass(), "must be"); - assert(k->oop_is_instance(), "cast to InstanceKlass"); + assert(k == NULL || k->is_klass(), "must be"); + assert(k == NULL || k->oop_is_instance(), "cast to InstanceKlass"); return (InstanceKlass*) k; } diff -r e48e953c86e8 -r 4bbf0e9196f2 src/share/vm/prims/jvmtiRedefineClasses.cpp --- a/src/share/vm/prims/jvmtiRedefineClasses.cpp Mon Sep 28 14:53:13 2015 -0700 +++ b/src/share/vm/prims/jvmtiRedefineClasses.cpp Mon Sep 28 15:01:41 2015 -0700 @@ -4071,9 +4071,6 @@ mnt->adjust_method_entries(the_class(), &trace_name_printed); } - // Fix Resolution Error table also to remove old constant pools - SystemDictionary::delete_resolution_error(old_constants); - if (the_class->oop_map_cache() != NULL) { // Flush references to any obsolete methods from the oop map cache // so that obsolete methods are not pinned. diff -r e48e953c86e8 -r 4bbf0e9196f2 src/share/vm/runtime/thread.cpp --- a/src/share/vm/runtime/thread.cpp Mon Sep 28 14:53:13 2015 -0700 +++ b/src/share/vm/runtime/thread.cpp Mon Sep 28 15:01:41 2015 -0700 @@ -3307,6 +3307,9 @@ extern void JDK_Version_init(); + // Preinitialize version info. + VM_Version::early_initialize(); + // Check version if (!is_supported_jni_version(args->version)) return JNI_EVERSION; diff -r e48e953c86e8 -r 4bbf0e9196f2 src/share/vm/runtime/vframe.cpp --- a/src/share/vm/runtime/vframe.cpp Mon Sep 28 14:53:13 2015 -0700 +++ b/src/share/vm/runtime/vframe.cpp Mon Sep 28 15:01:41 2015 -0700 @@ -148,8 +148,7 @@ if (obj.not_null()) { st->print("\t- %s <" INTPTR_FORMAT "> ", lock_state, (address)obj()); if (obj->klass() == SystemDictionary::Class_klass()) { - Klass* target_klass = java_lang_Class::as_Klass(obj()); - st->print_cr("(a java.lang.Class for %s)", InstanceKlass::cast(target_klass)->external_name()); + st->print_cr("(a java.lang.Class for %s)", java_lang_Class::as_external_name(obj())); } else { Klass* k = obj->klass(); st->print_cr("(a %s)", k->external_name()); diff -r e48e953c86e8 -r 4bbf0e9196f2 src/share/vm/runtime/vm_version.hpp --- a/src/share/vm/runtime/vm_version.hpp Mon Sep 28 14:53:13 2015 -0700 +++ b/src/share/vm/runtime/vm_version.hpp Mon Sep 28 15:01:41 2015 -0700 @@ -56,6 +56,13 @@ public: static void initialize(); + // This allows for early initialization of VM_Version information + // that may be needed later in the initialization sequence but before + // full VM_Version initialization is possible. It can not depend on any + // other part of the VM being initialized when called. Platforms that + // need to specialize this define VM_Version::early_initialize(). + static void early_initialize() { } + // Name static const char* vm_name(); // Vendor diff -r e48e953c86e8 -r 4bbf0e9196f2 test/runtime/RedefineFinalizer/RedefineFinalizer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/RedefineFinalizer/RedefineFinalizer.java Mon Sep 28 15:01:41 2015 -0700 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2014, 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. + */ + +/* + * @test + * @bug 6904403 + * @summary Don't assert if we redefine finalize method + * @library /testlibrary + * @build RedefineClassHelper + * @run main RedefineClassHelper + * @run main/othervm -javaagent:redefineagent.jar RedefineFinalizer + */ + +/* + * Regression test for hitting: + * + * assert(f == k->has_finalizer()) failed: inconsistent has_finalizer + * + * when redefining finalizer method + */ +public class RedefineFinalizer { + + public static String newB = + "class RedefineFinalizer$B {" + + " protected void finalize() { " + + " System.out.println(\"Finalizer called\");" + + " }" + + "}"; + + public static void main(String[] args) throws Exception { + RedefineClassHelper.redefineClass(B.class, newB); + + A a = new A(); + } + + static class A extends B { + } + + static class B { + protected void finalize() { + // should be empty + } + } +} diff -r e48e953c86e8 -r 4bbf0e9196f2 test/runtime/RedefineTests/RedefineRunningMethodsWithResolutionErrors.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/RedefineTests/RedefineRunningMethodsWithResolutionErrors.java Mon Sep 28 15:01:41 2015 -0700 @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2014, 2015, 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. + */ + +/* + * @test + * @bug 8076110 + * @summary Redefine running methods that have cached resolution errors + * @library /testlibrary + * @modules java.instrument + * java.base/jdk.internal.org.objectweb.asm + * @build RedefineClassHelper + * @run main RedefineClassHelper + * @run main/othervm -javaagent:redefineagent.jar RedefineRunningMethodsWithResolutionErrors + */ + +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Label; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; + +import java.lang.reflect.InvocationTargetException; + +public class RedefineRunningMethodsWithResolutionErrors extends ClassLoader implements Opcodes { + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + if (name.equals("C")) { + byte[] b = loadC(false); + return defineClass(name, b, 0, b.length); + } else { + return super.findClass(name); + } + } + + private static byte[] loadC(boolean redefine) { + ClassWriter cw = new ClassWriter(0); + + cw.visit(52, ACC_SUPER | ACC_PUBLIC, "C", null, "java/lang/Object", null); + { + MethodVisitor mv; + + mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "m", "()V", null, null); + mv.visitCode(); + + // First time we run we will: + // 1) Cache resolution errors + // 2) Redefine the class / method + // 3) Try to read the resolution errors that were cached + // + // The redefined method will never run, throw error to be sure + if (redefine) { + createThrowRuntimeExceptionCode(mv, "The redefined method was called"); + } else { + createMethodBody(mv); + } + mv.visitMaxs(3, 0); + mv.visitEnd(); + } + cw.visitEnd(); + return cw.toByteArray(); + } + + private static void createMethodBody(MethodVisitor mv) { + Label classExists = new Label(); + + // Cache resolution errors + createLoadNonExistentClassCode(mv, classExists); + + // Redefine our own class and method + mv.visitMethodInsn(INVOKESTATIC, "RedefineRunningMethodsWithResolutionErrors", "redefine", "()V"); + + // Provoke the same error again to make sure the resolution error cache works + createLoadNonExistentClassCode(mv, classExists); + + // Test passed + mv.visitInsn(RETURN); + + mv.visitFrame(F_SAME, 0, new Object[0], 0, new Object[0]); + mv.visitLabel(classExists); + + createThrowRuntimeExceptionCode(mv, "Loaded class that shouldn't exist (\"NonExistentClass\")"); + } + + private static void createLoadNonExistentClassCode(MethodVisitor mv, Label classExists) { + Label tryLoadBegin = new Label(); + Label tryLoadEnd = new Label(); + Label catchLoadBlock = new Label(); + mv.visitTryCatchBlock(tryLoadBegin, tryLoadEnd, catchLoadBlock, "java/lang/NoClassDefFoundError"); + + // Try to load a class that does not exist to provoke resolution errors + mv.visitLabel(tryLoadBegin); + mv.visitMethodInsn(INVOKESTATIC, "NonExistentClass", "nonExistentMethod", "()V"); + mv.visitLabel(tryLoadEnd); + + // No NoClassDefFoundError means NonExistentClass existed, which shouldn't happen + mv.visitJumpInsn(GOTO, classExists); + + mv.visitFrame(F_SAME1, 0, new Object[0], 1, new Object[] { "java/lang/NoClassDefFoundError" }); + mv.visitLabel(catchLoadBlock); + + // Ignore the expected NoClassDefFoundError + mv.visitInsn(POP); + } + + private static void createThrowRuntimeExceptionCode(MethodVisitor mv, String msg) { + mv.visitTypeInsn(NEW, "java/lang/RuntimeException"); + mv.visitInsn(DUP); + mv.visitLdcInsn(msg); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "", "(Ljava/lang/String;)V"); + mv.visitInsn(ATHROW); + } + + private static Class c; + + public static void redefine() throws Exception { + RedefineClassHelper.redefineClass(c, loadC(true)); + } + + public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { + c = Class.forName("C", true, new RedefineRunningMethodsWithResolutionErrors()); + c.getMethod("m").invoke(null); + } +} diff -r e48e953c86e8 -r 4bbf0e9196f2 test/testlibrary/RedefineClassHelper.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/testlibrary/RedefineClassHelper.java Mon Sep 28 15:01:41 2015 -0700 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2014, 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. + */ + +import java.io.PrintWriter; +import java.lang.instrument.*; +import com.oracle.java.testlibrary.*; + +/* + * Helper class to write tests that redefine classes. + * When main method is run, it will create a redefineagent.jar that can be used + * with the -javaagent option to support redefining classes in jtreg tests. + * + * See sample test in test/testlibrary_tests/RedefineClassTest.java + */ +public class RedefineClassHelper { + + public static Instrumentation instrumentation; + public static void premain(String agentArgs, Instrumentation inst) { + instrumentation = inst; + } + + /** + * Redefine a class + * + * @param clazz Class to redefine + * @param javacode String with the new java code for the class to be redefined + */ + public static void redefineClass(Class clazz, String javacode) throws Exception { + byte[] bytecode = InMemoryJavaCompiler.compile(clazz.getName(), javacode); + redefineClass(clazz, bytecode); + } + + /** + * Redefine a class + * + * @param clazz Class to redefine + * @param bytecode byte[] with the new class + */ + public static void redefineClass(Class clazz, byte[] bytecode) throws Exception { + instrumentation.redefineClasses(new ClassDefinition(clazz, bytecode)); + } + + /** + * Main method to be invoked before test to create the redefineagent.jar + */ + public static void main(String[] args) throws Exception { + ClassFileInstaller.main("RedefineClassHelper"); + + PrintWriter pw = new PrintWriter("MANIFEST.MF"); + pw.println("Premain-Class: RedefineClassHelper"); + pw.println("Can-Redefine-Classes: true"); + pw.close(); + + sun.tools.jar.Main jarTool = new sun.tools.jar.Main(System.out, System.err, "jar"); + if (!jarTool.run(new String[] { "-cmf", "MANIFEST.MF", "redefineagent.jar", "RedefineClassHelper.class" })) { + throw new Exception("jar operation failed"); + } + } +} diff -r e48e953c86e8 -r 4bbf0e9196f2 test/testlibrary_tests/RedefineClassTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/testlibrary_tests/RedefineClassTest.java Mon Sep 28 15:01:41 2015 -0700 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2014, 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. + */ + +/* + * @test + * @library /testlibrary + * @summary Proof of concept test for RedefineClassHelper + * @build RedefineClassHelper + * @run main RedefineClassHelper + * @run main/othervm -javaagent:redefineagent.jar RedefineClassTest + */ + +import static com.oracle.java.testlibrary.Asserts.*; +import com.oracle.java.testlibrary.*; + +/* + * Proof of concept test for the test utility class RedefineClassHelper + */ +public class RedefineClassTest { + + public static String newClass = "class RedefineClassTest$A { public int Method() { return 2; } }"; + public static void main(String[] args) throws Exception { + A a = new A(); + assertTrue(a.Method() == 1); + RedefineClassHelper.redefineClass(A.class, newClass); + assertTrue(a.Method() == 2); + } + + static class A { + public int Method() { + return 1; + } + } +}