author | iklam |
Wed, 17 Oct 2018 15:57:10 -0700 | |
changeset 52319 | 625f6c742392 |
parent 52318 | 124af9276e44 |
child 52320 | 26777794ade5 |
--- a/src/hotspot/share/classfile/javaClasses.cpp Mon Oct 29 12:33:41 2018 -0700 +++ b/src/hotspot/share/classfile/javaClasses.cpp Wed Oct 17 15:57:10 2018 -0700 @@ -50,6 +50,7 @@ #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" #include "oops/typeArrayOop.inline.hpp" +#include "prims/jvmtiExport.hpp" #include "prims/resolvedMethodTable.hpp" #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/frame.inline.hpp" @@ -125,7 +126,7 @@ if (ik == NULL) { ResourceMark rm; log_error(class)("Mismatch JDK version for field: %s type: %s", name_symbol->as_C_string(), signature_symbol->as_C_string()); - vm_exit_during_initialization("Invalid layout of preloaded class"); + vm_exit_during_initialization("Invalid layout of well-known class"); } if (!ik->find_local_field(name_symbol, signature_symbol, &fd) || fd.is_static() != is_static) { @@ -138,7 +139,7 @@ LogStream ls(lt.error()); ik->print_on(&ls); #endif //PRODUCT - vm_exit_during_initialization("Invalid layout of preloaded class: use -Xlog:class+load=info to see the origin of the problem class"); + vm_exit_during_initialization("Invalid layout of well-known class: use -Xlog:class+load=info to see the origin of the problem class"); } dest_offset = fd.offset(); } @@ -151,7 +152,7 @@ if (name == NULL) { ResourceMark rm; log_error(class)("Name %s should be in the SymbolTable since its class is loaded", name_string); - vm_exit_during_initialization("Invalid layout of preloaded class", ik->external_name()); + vm_exit_during_initialization("Invalid layout of well-known class", ik->external_name()); } compute_offset(dest_offset, ik, name, signature_symbol, is_static); } @@ -1196,7 +1197,7 @@ Handle class_loader, Handle module, Handle protection_domain, TRAPS) { // Postpone restoring archived mirror until java.lang.Class is loaded. Please - // see more details in SystemDictionary::resolve_preloaded_classes(). + // see more details in SystemDictionary::resolve_well_known_classes(). if (!SystemDictionary::Class_klass_loaded()) { assert(fixup_mirror_list() != NULL, "fixup_mirror_list not initialized"); fixup_mirror_list()->push(k); @@ -4250,12 +4251,19 @@ // Compute non-hard-coded field offsets of all the classes in this file void JavaClasses::compute_offsets() { if (UseSharedSpaces) { - return; // field offsets are loaded from archive + assert(JvmtiExport::is_early_phase() && !(JvmtiExport::should_post_class_file_load_hook() && + JvmtiExport::has_early_class_hook_env()), + "JavaClasses::compute_offsets() must be called in early JVMTI phase."); + // None of the classes used by the rest of this function can be replaced by + // JMVTI ClassFileLoadHook. + // We are safe to use the archived offsets, which have already been restored + // by JavaClasses::serialize_offsets, without computing the offsets again. + return; } // We have already called the compute_offsets() of the // BASIC_JAVA_CLASSES_DO_PART1 classes (java_lang_String and java_lang_Class) - // earlier inside SystemDictionary::resolve_preloaded_classes() + // earlier inside SystemDictionary::resolve_well_known_classes() BASIC_JAVA_CLASSES_DO_PART2(DO_COMPUTE_OFFSETS); // generated interpreter code wants to know about the offsets we just computed: @@ -4356,7 +4364,7 @@ tty->print_cr(" name: %s, sig: %s, flags: %08x", fs.name()->as_C_string(), fs.signature()->as_C_string(), fs.access_flags().as_int()); } #endif //PRODUCT - vm_exit_during_initialization("Invalid layout of preloaded class: use -Xlog:class+load=info to see the origin of the problem class"); + vm_exit_during_initialization("Invalid layout of well-known class: use -Xlog:class+load=info to see the origin of the problem class"); return -1; }
--- a/src/hotspot/share/classfile/systemDictionary.cpp Mon Oct 29 12:33:41 2018 -0700 +++ b/src/hotspot/share/classfile/systemDictionary.cpp Wed Oct 17 15:57:10 2018 -0700 @@ -67,7 +67,7 @@ #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" #include "oops/typeArrayKlass.hpp" -#include "prims/jvmtiEnvBase.hpp" +#include "prims/jvmtiExport.hpp" #include "prims/resolvedMethodTable.hpp" #include "prims/methodHandles.hpp" #include "runtime/arguments.hpp" @@ -1489,8 +1489,7 @@ !search_only_bootloader_append, "Attempt to load a class outside of boot loader's module path"); - // Search the shared system dictionary for classes preloaded into the - // shared spaces. + // Search for classes in the CDS archive. InstanceKlass* k = NULL; { #if INCLUDE_CDS @@ -1958,7 +1957,7 @@ // Allocate private object used as system class loader lock _system_loader_lock_obj = oopFactory::new_intArray(0, CHECK); // Initialize basic classes - resolve_preloaded_classes(CHECK); + resolve_well_known_classes(CHECK); } // Compact table of directions on the initialization of klasses: @@ -1971,6 +1970,19 @@ 0 }; +#ifdef ASSERT +bool SystemDictionary::is_well_known_klass(Symbol* class_name) { + int sid; + for (int i = 0; (sid = wk_init_info[i]) != 0; i++) { + Symbol* symbol = vmSymbols::symbol_at((vmSymbols::SID)sid); + if (class_name == symbol) { + return true; + } + } + return false; +} +#endif + bool SystemDictionary::resolve_wk_klass(WKID id, TRAPS) { assert(id >= (int)FIRST_WKID && id < (int)WKID_LIMIT, "oob"); int sid = wk_init_info[id - FIRST_WKID]; @@ -2002,8 +2014,8 @@ start_id = limit_id; } -void SystemDictionary::resolve_preloaded_classes(TRAPS) { - assert(WK_KLASS(Object_klass) == NULL, "preloaded classes should only be initialized once"); +void SystemDictionary::resolve_well_known_classes(TRAPS) { + assert(WK_KLASS(Object_klass) == NULL, "well-known classes should only be initialized once"); // Create the ModuleEntry for java.base. This call needs to be done here, // after vmSymbols::initialize() is called but before any classes are pre-loaded. @@ -2071,7 +2083,8 @@ WKID jsr292_group_end = WK_KLASS_ENUM_NAME(VolatileCallSite_klass); resolve_wk_klasses_until(jsr292_group_start, scan, CHECK); resolve_wk_klasses_through(jsr292_group_end, scan, CHECK); - resolve_wk_klasses_until(NOT_JVMCI(WKID_LIMIT) JVMCI_ONLY(FIRST_JVMCI_WKID), scan, CHECK); + WKID last = NOT_JVMCI(WKID_LIMIT) JVMCI_ONLY(FIRST_JVMCI_WKID); + resolve_wk_klasses_until(last, scan, CHECK); _box_klasses[T_BOOLEAN] = WK_KLASS(Boolean_klass); _box_klasses[T_CHAR] = WK_KLASS(Character_klass); @@ -2088,6 +2101,17 @@ Method* method = InstanceKlass::cast(ClassLoader_klass())->find_method(vmSymbols::checkPackageAccess_name(), vmSymbols::class_protectiondomain_signature()); _has_checkPackageAccess = (method != NULL); } + +#ifdef ASSERT + if (UseSharedSpaces) { + assert(JvmtiExport::is_early_phase(), + "All well known classes must be resolved in JVMTI early phase"); + for (int i = FIRST_WKID; i < last; i++) { + InstanceKlass* k = _well_known_klasses[i]; + assert(k->is_shared(), "must not be replaced by JVMTI class file load hook"); + } + } +#endif } // Tells if a given klass is a box (wrapper class, such as java.lang.Integer).
--- a/src/hotspot/share/classfile/systemDictionary.hpp Mon Oct 29 12:33:41 2018 -0700 +++ b/src/hotspot/share/classfile/systemDictionary.hpp Wed Oct 17 15:57:10 2018 -0700 @@ -85,19 +85,20 @@ class GCTimer; class OopStorage; -// Certain classes are preloaded, such as java.lang.Object and java.lang.String. -// They are all "well-known", in the sense that no class loader is allowed +#define WK_KLASS_ENUM_NAME(kname) kname##_knum + +// Certain classes, such as java.lang.Object and java.lang.String, +// are "well-known", in the sense that no class loader is allowed // to provide a different definition. // -// These klasses must all have names defined in vmSymbols. - -#define WK_KLASS_ENUM_NAME(kname) kname##_knum - // Each well-known class has a short klass name (like object_klass), // and a vmSymbol name (like java_lang_Object). -// The order of these definitions is significant; it is the order in which -// preloading is actually performed by resolve_preloaded_classes. - +// +// The order of these definitions is significant: the classes are +// resolved during early VM start-up by resolve_well_known_classes +// in this order. Changing the order may require careful restructuring +// of the VM start-up sequence. +// #define WK_KLASSES_DO(do_klass) \ /* well-known classes */ \ do_klass(Object_klass, java_lang_Object ) \ @@ -127,7 +128,7 @@ do_klass(IllegalMonitorStateException_klass, java_lang_IllegalMonitorStateException ) \ do_klass(Reference_klass, java_lang_ref_Reference ) \ \ - /* Preload ref klasses and set reference types */ \ + /* ref klasses and set reference types */ \ do_klass(SoftReference_klass, java_lang_ref_SoftReference ) \ do_klass(WeakReference_klass, java_lang_ref_WeakReference ) \ do_klass(FinalReference_klass, java_lang_ref_FinalReference ) \ @@ -200,7 +201,7 @@ /* support for stack dump lock analysis */ \ do_klass(java_util_concurrent_locks_AbstractOwnableSynchronizer_klass, java_util_concurrent_locks_AbstractOwnableSynchronizer) \ \ - /* Preload boxing klasses */ \ + /* boxing klasses */ \ do_klass(Boolean_klass, java_lang_Boolean ) \ do_klass(Character_klass, java_lang_Character ) \ do_klass(Float_klass, java_lang_Float ) \ @@ -391,7 +392,8 @@ // Initialization static void initialize(TRAPS); - // Checked fast access to commonly used classes - mostly preloaded + // Checked fast access to the well-known classes -- so that you don't try to use them + // before they are resolved. static InstanceKlass* check_klass(InstanceKlass* k) { assert(k != NULL, "klass not loaded"); return k; @@ -435,6 +437,12 @@ return check_klass(_box_klasses[t]); } static BasicType box_klass_type(Klass* k); // inverse of box_klass +#ifdef ASSERT + static bool is_well_known_klass(Klass* k) { + return is_well_known_klass(k->name()); + } + static bool is_well_known_klass(Symbol* class_name); +#endif protected: // Returns the class loader data to be used when looking up/updating the @@ -695,8 +703,8 @@ ClassLoaderData* loader_data, TRAPS); - // Resolve preloaded classes so they can be used like SystemDictionary::String_klass() - static void resolve_preloaded_classes(TRAPS); + // Resolve well-known classes so they can be used like SystemDictionary::String_klass() + static void resolve_well_known_classes(TRAPS); // Class loader constraints static void check_constraints(unsigned int hash, @@ -707,7 +715,6 @@ InstanceKlass* k, Handle loader, TRAPS); - // Variables holding commonly used klasses (preloaded) static InstanceKlass* _well_known_klasses[]; // table of box klasses (int_klass, etc.)
--- a/src/hotspot/share/memory/filemap.cpp Mon Oct 29 12:33:41 2018 -0700 +++ b/src/hotspot/share/memory/filemap.cpp Wed Oct 17 15:57:10 2018 -0700 @@ -914,6 +914,19 @@ return; } + if (JvmtiExport::should_post_class_file_load_hook() && JvmtiExport::has_early_class_hook_env()) { + ShouldNotReachHere(); // CDS should have been disabled. + // The archived objects are mapped at JVM start-up, but we don't know if + // j.l.String or j.l.Class might be replaced by the ClassFileLoadHook, + // which would make the archived String or mirror objects invalid. Let's be safe and not + // use the archived objects. These 2 classes are loaded during the JVMTI "early" stage. + // + // If JvmtiExport::has_early_class_hook_env() is false, the classes of some objects + // in the archived subgraphs may be replaced by the ClassFileLoadHook. But that's OK + // because we won't install an archived object subgraph if the klass of any of the + // referenced objects are replaced. See HeapShared::initialize_from_archived_subgraph(). + } + MemRegion heap_reserved = Universe::heap()->reserved_region(); log_info(cds)("CDS archive was created with max heap size = " SIZE_FORMAT "M, and the following configuration:", @@ -1224,6 +1237,15 @@ bool FileMapInfo::initialize() { assert(UseSharedSpaces, "UseSharedSpaces expected."); + if (JvmtiExport::should_post_class_file_load_hook() && JvmtiExport::has_early_class_hook_env()) { + // CDS assumes that no classes resolved in SystemDictionary::resolve_well_known_classes + // are replaced at runtime by JVMTI ClassFileLoadHook. All of those classes are resolved + // during the JVMTI "early" stage, so we can still use CDS if + // JvmtiExport::has_early_class_hook_env() is false. + FileMapInfo::fail_continue("CDS is disabled because early JVMTI ClassFileLoadHook is in use."); + return false; + } + if (!open_for_read()) { return false; }
--- a/src/hotspot/share/memory/heapShared.cpp Mon Oct 29 12:33:41 2018 -0700 +++ b/src/hotspot/share/memory/heapShared.cpp Wed Oct 17 15:57:10 2018 -0700 @@ -417,6 +417,11 @@ Klass* resolved_k = SystemDictionary::resolve_or_null( (obj_k)->name(), THREAD); if (resolved_k != obj_k) { + assert(!SystemDictionary::is_well_known_klass(resolved_k), + "shared well-known classes must not be replaced by JVMTI ClassFileLoadHook"); + ResourceMark rm(THREAD); + log_info(cds, heap)("Failed to load subgraph because %s was not loaded from archive", + resolved_k->external_name()); return; } if ((obj_k)->is_instance_klass()) {
--- a/src/hotspot/share/prims/jvmtiExport.cpp Mon Oct 29 12:33:41 2018 -0700 +++ b/src/hotspot/share/prims/jvmtiExport.cpp Wed Oct 17 15:57:10 2018 -0700 @@ -994,6 +994,20 @@ } }; +bool JvmtiExport::is_early_phase() { + return JvmtiEnvBase::get_phase() <= JVMTI_PHASE_PRIMORDIAL; +} + +bool JvmtiExport::has_early_class_hook_env() { + JvmtiEnvIterator it; + for (JvmtiEnv* env = it.first(); env != NULL; env = it.next(env)) { + if (env->early_class_hook_env()) { + return true; + } + } + return false; +} + bool JvmtiExport::_should_post_class_file_load_hook = false; // this entry is for class file load hook on class load, redefine and retransform
--- a/src/hotspot/share/prims/jvmtiExport.hpp Mon Oct 29 12:33:41 2018 -0700 +++ b/src/hotspot/share/prims/jvmtiExport.hpp Wed Oct 17 15:57:10 2018 -0700 @@ -328,6 +328,8 @@ JVMTI_ONLY(return _should_post_class_file_load_hook); NOT_JVMTI(return false;) } + static bool is_early_phase(); + static bool has_early_class_hook_env(); // Return true if the class was modified by the hook. static bool post_class_file_load_hook(Symbol* h_name, Handle class_loader, Handle h_protection_domain,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/hotspot/jtreg/runtime/SharedArchiveFile/serviceability/ReplaceCriticalClasses.java Wed Oct 17 15:57:10 2018 -0700 @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2018, 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 + * @summary Tests how CDS works when critical library classes are replaced with JVMTI ClassFileLoadHook + * @library /test/lib + * @requires vm.cds + * @build sun.hotspot.WhiteBox + * @run driver ClassFileInstaller -jar whitebox.jar sun.hotspot.WhiteBox + * @run main/othervm/native ReplaceCriticalClasses + */ + +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import jdk.test.lib.cds.CDSTestUtils; +import jdk.test.lib.cds.CDSOptions; +import jdk.test.lib.process.OutputAnalyzer; +import sun.hotspot.WhiteBox; + +public class ReplaceCriticalClasses { + public static void main(String args[]) throws Throwable { + if (args.length == 0) { + launchChildProcesses(); + } else if (args.length == 3 && args[0].equals("child")) { + Class klass = Class.forName(args[2].replace("/", ".")); + if (args[1].equals("-shared")) { + testInChild(true, klass); + } else if (args[1].equals("-notshared")) { + testInChild(false, klass); + } else { + throw new RuntimeException("Unknown child exec option " + args[1]); + } + return; + } else { + throw new RuntimeException("Usage: @run main/othervm/native ReplaceCriticalClasses"); + } + } + + static void launchChildProcesses() throws Throwable { + String tests[] = { + // CDS should be disabled -- these critical classes will be replaced + // because JvmtiExport::early_class_hook_env() is true. + "-early -notshared java/lang/Object", + "-early -notshared java/lang/String", + "-early -notshared java/lang/Cloneable", + "-early -notshared java/io/Serializable", + + // CDS should not be disabled -- these critical classes cannot be replaced because + // JvmtiExport::early_class_hook_env() is false. + "java/lang/Object", + "java/lang/String", + "java/lang/Cloneable", + "java/io/Serializable", + + // Try to replace classes that are used by the archived subgraph graphs. + "-subgraph java/util/ArrayList", + "-subgraph java/lang/module/ResolvedModule", + + // Replace classes that are loaded after JVMTI_PHASE_PRIMORDIAL. It's OK to replace such + // classes even when CDS is enabled. Nothing bad should happen. + "-notshared jdk/internal/vm/PostVMInitHook", + "-notshared java/util/Locale", + "-notshared sun/util/locale/BaseLocale", + "-notshared java/lang/Readable", + }; + + int n = 0; + for (String s : tests) { + System.out.println("Test case[" + (n++) + "] = \"" + s + "\""); + String args[] = s.split("\\s+"); // split by space character + launchChild(args); + } + } + + static void launchChild(String args[]) throws Throwable { + if (args.length < 1) { + throw new RuntimeException("Invalid test case. Should be <-early> <-subgraph> <-notshared> klassName"); + } + String klassName = null; + String early = ""; + boolean subgraph = false; + String shared = "-shared"; + + for (int i=0; i<args.length-1; i++) { + String opt = args[i]; + if (opt.equals("-early")) { + early = "-early,"; + } else if (opt.equals("-subgraph")) { + subgraph = true; + } else if (opt.equals("-notshared")) { + shared = opt; + } else { + throw new RuntimeException("Unknown option: " + opt); + } + } + klassName = args[args.length-1]; + Class.forName(klassName.replace("/", ".")); // make sure it's a valid class + + // We will pass an option like "-agentlib:SimpleClassFileLoadHook=java/util/Locale,XXX,XXX". + // The SimpleClassFileLoadHook agent would attempt to hook the java/util/Locale class + // but leave the class file bytes unchanged (it replaces all bytes "XXX" with "XXX", i.e., + // a no-op). JVMTI doesn't check the class file bytes returned by the agent, so as long + // as the agent returns a buffer, it will not load the class from CDS, and will instead + // load the class by parsing the buffer. + // + // Note that for safety we don't change the contents of the class file bytes. If in the + // future JVMTI starts checking the contents of the class file bytes, this test would need + // to be updated. (You'd see the test case with java/util/Locale staring to fail). + String agent = "-agentlib:SimpleClassFileLoadHook=" + early + klassName + ",XXX,XXX"; + + CDSOptions opts = (new CDSOptions()) + .setXShareMode("auto") + .setUseSystemArchive(true) + .setUseVersion(false) + .addSuffix("-showversion", + "-Xlog:cds", + "-XX:+UnlockDiagnosticVMOptions", + agent, + "-XX:+WhiteBoxAPI", + "-Xbootclasspath/a:" + ClassFileInstaller.getJarPath("whitebox.jar")); + + if (subgraph) { + opts.addSuffix("-Xlog:cds+heap", + "-Xlog:class+load"); + } + + opts.addSuffix("ReplaceCriticalClasses", + "child", + shared, + klassName); + + final boolean expectDisable = !early.equals(""); + final boolean checkSubgraph = subgraph; + CDSTestUtils.run(opts).assertNormalExit(out -> { + if (expectDisable) { + out.shouldContain("UseSharedSpaces: CDS is disabled because early JVMTI ClassFileLoadHook is in use."); + System.out.println("CDS disabled as expected"); + } + if (checkSubgraph) { + // As of 2018/10/21 the classes in the archived subgraphs won't be + // replaced because all archived subgraphs were loaded in JVMTI_PHASE_PRIMORDIAL. + // + // This is the first class to be loaded after JVMTI has exited JVMTI_PHASE_PRIMORDIAL. + // Make sure no subgraphs are loaded afterwards. + // + // Can't use out.shouldNotMatch() because that doesn't match across multiple lines. + String firstNonPrimordialClass = "jdk.jfr.internal.EventWriter"; + String regexp = firstNonPrimordialClass + ".*initialize_from_archived_subgraph"; + Pattern regex = Pattern.compile(regexp, Pattern.DOTALL); + Matcher matcher = regex.matcher(out.getStdout()); + if (matcher.find()) { + out.reportDiagnosticSummary(); + throw new RuntimeException("'" + regexp + + "' found in stdout: '" + matcher.group() + "' \n"); + } + } + }); + } + + static void testInChild(boolean shouldBeShared, Class klass) { + WhiteBox wb = WhiteBox.getWhiteBox(); + + if (shouldBeShared && !wb.isSharedClass(klass)) { + throw new RuntimeException(klass + " should be shared but but actually is not."); + } + if (!shouldBeShared && wb.isSharedClass(klass)) { + throw new RuntimeException(klass + " should not be shared but actually is."); + } + System.out.println("wb.isSharedClass(klass): " + wb.isSharedClass(klass) + " == " + shouldBeShared); + + String strings[] = { + // interned strings from j.l.Object + "@", + "nanosecond timeout value out of range", + "timeoutMillis value is negative", + + // interned strings from j.l.Integer + "0", + "0X", + "0x", + "int" + }; + + // Make sure the interned string table is same + for (String s : strings) { + String i = s.intern(); + if (s != i) { + throw new RuntimeException("Interned string mismatch: \"" + s + "\" @ " + System.identityHashCode(s) + + " vs \"" + i + "\" @ " + System.identityHashCode(i)); + } + } + // We have tried to use ClassFileLoadHook to replace critical library classes (which may + // may not have succeeded, depending on whether the agent has requested + // can_generate_all_class_hook_events/can_generate_early_class_hook_events capabilities). + // + // In any case, the JVM should have started properly (perhaps with CDS disabled) and + // the above operations should succeed. + System.out.println("If I can come to here without crashing, things should be OK"); + } +}
--- a/test/hotspot/jtreg/testlibrary/jvmti/libSimpleClassFileLoadHook.c Mon Oct 29 12:33:41 2018 -0700 +++ b/test/hotspot/jtreg/testlibrary/jvmti/libSimpleClassFileLoadHook.c Wed Oct 17 15:57:10 2018 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2018, 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 @@ -91,17 +91,23 @@ *new_class_data_len = class_data_len; *new_class_data = new_data; - fprintf(stderr, "Rewriting done. Replaced %d occurrence(s)\n", count); + fprintf(stderr, "Rewriting done. Replaced %d occurrence(s) of \"%s\" to \"%s\"\n", count, FROM, TO); } } } +static int early = 0; + static jint init_options(char *options) { char* class_name; char* from; char* to; fprintf(stderr, "Agent library loaded with options = %s\n", options); + if (options != NULL && strncmp(options, "-early,", 7) == 0) { + early = 1; + options += 7; + } if ((class_name = options) != NULL && (from = strchr(class_name, ',')) != NULL && (from[1] != 0)) { *from = 0; @@ -132,6 +138,7 @@ static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { int rc; + jvmtiCapabilities caps; if ((rc = (*jvm)->GetEnv(jvm, (void **)&jvmti, JVMTI_VERSION_1_1)) != JNI_OK) { fprintf(stderr, "Unable to create jvmtiEnv, GetEnv failed, error = %d\n", rc); @@ -141,6 +148,19 @@ return JNI_ERR; } + memset(&caps, 0, sizeof(caps)); + + caps.can_redefine_classes = 1; + if (early) { + fprintf(stderr, "can_generate_all_class_hook_events/can_generate_early_vmstart/can_generate_early_class_hook_events == 1\n"); + caps.can_generate_all_class_hook_events = 1; + caps.can_generate_early_class_hook_events = 1; + } + if ((rc = (*jvmti)->AddCapabilities(jvmti, &caps)) != JNI_OK) { + fprintf(stderr, "AddCapabilities failed, error = %d\n", rc); + return JNI_ERR; + } + (void) memset(&callbacks, 0, sizeof(callbacks)); callbacks.ClassFileLoadHook = &ClassFileLoadHook; if ((rc = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(callbacks))) != JNI_OK) {
--- a/test/lib/jdk/test/lib/cds/CDSOptions.java Mon Oct 29 12:33:41 2018 -0700 +++ b/test/lib/jdk/test/lib/cds/CDSOptions.java Wed Oct 17 15:57:10 2018 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, 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 @@ -31,6 +31,7 @@ public String archiveName; public ArrayList<String> prefix = new ArrayList<String>(); public ArrayList<String> suffix = new ArrayList<String>(); + public boolean useSystemArchive = false; // Indicate whether to append "-version" when using CDS Archive. // Most of tests will use '-version' @@ -68,4 +69,9 @@ this.useVersion = use; return this; } + + public CDSOptions setUseSystemArchive(boolean use) { + this.useSystemArchive = use; + return this; + } }
--- a/test/lib/jdk/test/lib/cds/CDSTestUtils.java Mon Oct 29 12:33:41 2018 -0700 +++ b/test/lib/jdk/test/lib/cds/CDSTestUtils.java Wed Oct 17 15:57:10 2018 -0700 @@ -82,21 +82,21 @@ * * Instead, the test case should be written as * - * CCDSTestUtils.run(args).assertNormalExit("Hi"); + * CDSTestUtils.run(args).assertNormalExit("Hi"); * * EXAMPLES/HOWTO * * 1. For simple substring matching: * - * CCDSTestUtils.run(args).assertNormalExit("Hi"); - * CCDSTestUtils.run(args).assertNormalExit("a", "b", "x"); - * CCDSTestUtils.run(args).assertAbnormalExit("failure 1", "failure2"); + * CDSTestUtils.run(args).assertNormalExit("Hi"); + * CDSTestUtils.run(args).assertNormalExit("a", "b", "x"); + * CDSTestUtils.run(args).assertAbnormalExit("failure 1", "failure2"); * * 2. For more complex output matching: using Lambda expressions * - * CCDSTestUtils.run(args) + * CDSTestUtils.run(args) * .assertNormalExit(output -> output.shouldNotContain("this should not be printed"); - * CCDSTestUtils.run(args) + * CDSTestUtils.run(args) * .assertAbnormalExit(output -> { * output.shouldNotContain("this should not be printed"); * output.shouldHaveExitValue(123); @@ -104,13 +104,13 @@ * * 3. Chaining several checks: * - * CCDSTestUtils.run(args) + * CDSTestUtils.run(args) * .assertNormalExit(output -> output.shouldNotContain("this should not be printed") * .assertNormalExit("should have this", "should have that"); * * 4. [Rare use case] if a test sometimes exit normally, and sometimes abnormally: * - * CCDSTestUtils.run(args) + * CDSTestUtils.run(args) * .ifNormalExit("ths string is printed when exiting with 0") * .ifAbNormalExit("ths string is printed when exiting with 1"); * @@ -388,9 +388,11 @@ cmd.add("-Xshare:" + opts.xShareMode); cmd.add("-Dtest.timeout.factor=" + TestTimeoutFactor); - if (opts.archiveName == null) - opts.archiveName = getDefaultArchiveName(); - cmd.add("-XX:SharedArchiveFile=" + opts.archiveName); + if (!opts.useSystemArchive) { + if (opts.archiveName == null) + opts.archiveName = getDefaultArchiveName(); + cmd.add("-XX:SharedArchiveFile=" + opts.archiveName); + } if (opts.useVersion) cmd.add("-version");