8232080: jlink plugins for vendor information and run-time options
authormr
Tue, 29 Oct 2019 08:26:55 -0700
changeset 58842 6c255334120d
parent 58836 31ec3e55fa3d
child 58843 63994dedec49
8232080: jlink plugins for vendor information and run-time options Reviewed-by: ihse, alanb, kvn, bobv, mchung
make/autoconf/jdk-version.m4
make/autoconf/version-numbers
make/gensrc/GensrcMisc.gmk
src/hotspot/share/classfile/classLoader.cpp
src/hotspot/share/classfile/classLoader.hpp
src/hotspot/share/classfile/vmSymbols.hpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp
src/hotspot/share/runtime/arguments.cpp
src/hotspot/share/runtime/arguments.hpp
src/hotspot/share/runtime/flags/jvmFlag.cpp
src/hotspot/share/runtime/flags/jvmFlag.hpp
src/hotspot/share/runtime/java.cpp
src/hotspot/share/runtime/java.hpp
src/hotspot/share/runtime/thread.cpp
src/hotspot/share/runtime/vmStructs.cpp
src/hotspot/share/utilities/vmError.cpp
src/java.base/share/classes/java/lang/VersionProps.java.template
src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Flags.java
src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java
src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginConfiguration.java
src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java
src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/AddOptionsPlugin.java
src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/AddResourcePlugin.java
src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/VendorBugURLPlugin.java
src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/VendorVMBugURLPlugin.java
src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/VendorVersionPlugin.java
src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/VersionPropsPlugin.java
src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/Plugin.java
src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties
src/jdk.jlink/share/classes/module-info.java
test/jdk/tools/jlink/plugins/AddOptionsPluginTest.java
test/jdk/tools/jlink/plugins/VendorInfoPluginsTest.java
test/lib/jdk/test/lib/cds/CDSTestUtils.java
--- a/make/autoconf/jdk-version.m4	Tue Oct 29 11:33:25 2019 +0100
+++ b/make/autoconf/jdk-version.m4	Tue Oct 29 08:26:55 2019 -0700
@@ -162,7 +162,9 @@
     AC_MSG_ERROR([--with-vendor-vm-bug-url must have a value])
   elif [ ! [[ $with_vendor_vm_bug_url =~ ^[[:print:]]*$ ]] ]; then
     AC_MSG_ERROR([--with-vendor-vm-bug-url contains non-printing characters: $with_vendor_vm_bug_url])
-  else
+  elif test "x$with_vendor_vm_bug_url" != x; then
+    # Only set VENDOR_URL_VM_BUG if '--with-vendor-vm-bug-url' was used and is not empty.
+    # Otherwise we will use the value from "version-numbers" included above.
     VENDOR_URL_VM_BUG="$with_vendor_vm_bug_url"
   fi
   AC_SUBST(VENDOR_URL_VM_BUG)
--- a/make/autoconf/version-numbers	Tue Oct 29 11:33:25 2019 +0100
+++ b/make/autoconf/version-numbers	Tue Oct 29 08:26:55 2019 -0700
@@ -23,7 +23,8 @@
 # questions.
 #
 
-# Default version numbers to use unless overridden by configure
+# Default version, product, and vendor information to use,
+# unless overridden by configure
 
 DEFAULT_VERSION_FEATURE=14
 DEFAULT_VERSION_INTERIM=0
@@ -47,6 +48,7 @@
 HOTSPOT_VM_DISTRO="OpenJDK"
 VENDOR_URL=https://openjdk.java.net/
 VENDOR_URL_BUG=https://bugreport.java.com/bugreport/
+VENDOR_URL_VM_BUG=https://bugreport.java.com/bugreport/crash.jsp
 
 # Might need better names for these
 MACOSX_BUNDLE_NAME_BASE="OpenJDK"
--- a/make/gensrc/GensrcMisc.gmk	Tue Oct 29 11:33:25 2019 +0100
+++ b/make/gensrc/GensrcMisc.gmk	Tue Oct 29 08:26:55 2019 -0700
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2019, 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
@@ -46,7 +46,8 @@
         @@VENDOR_VERSION_STRING@@ => $(VENDOR_VERSION_STRING) ; \
         @@VENDOR@@ => $(COMPANY_NAME) ; \
         @@VENDOR_URL@@ => $(VENDOR_URL) ; \
-        @@VENDOR_URL_BUG@@ => $(VENDOR_URL_BUG), \
+        @@VENDOR_URL_BUG@@ => $(VENDOR_URL_BUG) ; \
+        @@VENDOR_URL_VM_BUG@@ => $(VENDOR_URL_VM_BUG), \
 ))
 
 GENSRC_JAVA_BASE += $(BUILD_VERSION_JAVA)
--- a/src/hotspot/share/classfile/classLoader.cpp	Tue Oct 29 11:33:25 2019 +0100
+++ b/src/hotspot/share/classfile/classLoader.cpp	Tue Oct 29 08:26:55 2019 -0700
@@ -1529,9 +1529,41 @@
 
   // lookup zip library entry points
   load_zip_library();
-  // lookup jimage library entry points
+  // jimage library entry points are loaded below, in lookup_vm_options
+  setup_bootstrap_search_path();
+}
+
+char* lookup_vm_resource(JImageFile *jimage, const char *jimage_version, const char *path) {
+  jlong size;
+  JImageLocationRef location = (*JImageFindResource)(jimage, "java.base", jimage_version, path, &size);
+  if (location == 0)
+    return NULL;
+  char *val = NEW_C_HEAP_ARRAY(char, size+1, mtClass);
+  (*JImageGetResource)(jimage, location, val, size);
+  val[size] = '\0';
+  return val;
+}
+
+// Lookup VM options embedded in the modules jimage file
+char* ClassLoader::lookup_vm_options() {
+  jint error;
+  char modules_path[JVM_MAXPATHLEN];
+  const char* fileSep = os::file_separator();
+
+  // Initialize jimage library entry points
   load_jimage_library();
-  setup_bootstrap_search_path();
+
+  jio_snprintf(modules_path, JVM_MAXPATHLEN, "%s%slib%smodules", Arguments::get_java_home(), fileSep, fileSep);
+  JImageFile* jimage =(*JImageOpen)(modules_path, &error);
+  if (jimage == NULL) {
+    return NULL;
+  }
+
+  const char *jimage_version = get_jimage_version_string();
+  char *options = lookup_vm_resource(jimage, jimage_version, "jdk/internal/vm/options");
+
+  (*JImageClose)(jimage);
+  return options;
 }
 
 #if INCLUDE_CDS
--- a/src/hotspot/share/classfile/classLoader.hpp	Tue Oct 29 11:33:25 2019 +0100
+++ b/src/hotspot/share/classfile/classLoader.hpp	Tue Oct 29 08:26:55 2019 -0700
@@ -411,6 +411,9 @@
   static char* skip_uri_protocol(char* source);
   static void  record_result(InstanceKlass* ik, const ClassFileStream* stream, TRAPS);
 #endif
+
+  static char* lookup_vm_options();
+
   static JImageLocationRef jimage_find_resource(JImageFile* jf, const char* module_name,
                                                 const char* file_name, jlong &size);
 
--- a/src/hotspot/share/classfile/vmSymbols.hpp	Tue Oct 29 11:33:25 2019 +0100
+++ b/src/hotspot/share/classfile/vmSymbols.hpp	Tue Oct 29 08:26:55 2019 -0700
@@ -135,6 +135,8 @@
   template(java_lang_VersionProps,                    "java/lang/VersionProps")                   \
   template(java_runtime_name_name,                    "java_runtime_name")                        \
   template(java_runtime_version_name,                 "java_runtime_version")                     \
+  template(java_runtime_vendor_version_name,          "VENDOR_VERSION")                           \
+  template(java_runtime_vendor_vm_bug_url_name,       "VENDOR_URL_VM_BUG")                        \
                                                                                                   \
   /* system initialization */                                                                     \
   template(initPhase1_name,                           "initPhase1")                               \
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp	Tue Oct 29 11:33:25 2019 +0100
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp	Tue Oct 29 08:26:55 2019 -0700
@@ -133,6 +133,7 @@
     case JVMFlag::ERGONOMIC: return "Ergonomic";
     case JVMFlag::ATTACH_ON_DEMAND: return "Attach on demand";
     case JVMFlag::INTERNAL: return "Internal";
+    case JVMFlag::JIMAGE_RESOURCE: return "JImage resource";
     default: ShouldNotReachHere(); return "";
   }
 }
--- a/src/hotspot/share/runtime/arguments.cpp	Tue Oct 29 11:33:25 2019 +0100
+++ b/src/hotspot/share/runtime/arguments.cpp	Tue Oct 29 08:26:55 2019 -0700
@@ -60,12 +60,6 @@
 #include "jfr/jfr.hpp"
 #endif
 
-// Note: This is a special bug reporting site for the JVM
-#ifdef VENDOR_URL_VM_BUG
-# define DEFAULT_VENDOR_URL_BUG VENDOR_URL_VM_BUG
-#else
-# define DEFAULT_VENDOR_URL_BUG "http://bugreport.java.com/bugreport/crash.jsp"
-#endif
 #define DEFAULT_JAVA_LAUNCHER  "generic"
 
 char*  Arguments::_jvm_flags_file               = NULL;
@@ -80,7 +74,7 @@
 Arguments::Mode Arguments::_mode                = _mixed;
 bool   Arguments::_java_compiler                = false;
 bool   Arguments::_xdebug_mode                  = false;
-const char*  Arguments::_java_vendor_url_bug    = DEFAULT_VENDOR_URL_BUG;
+const char*  Arguments::_java_vendor_url_bug    = NULL;
 const char*  Arguments::_sun_java_launcher      = DEFAULT_JAVA_LAUNCHER;
 bool   Arguments::_sun_java_launcher_is_altjvm  = false;
 
@@ -1422,12 +1416,16 @@
         os::free(old_java_command);
       }
     } else if (strcmp(key, "java.vendor.url.bug") == 0) {
+      // If this property is set on the command line then its value will be
+      // displayed in VM error logs as the URL at which to submit such logs.
+      // Normally the URL displayed in error logs is different from the value
+      // of this system property, so a different property should have been
+      // used here, but we leave this as-is in case someone depends upon it.
       const char* old_java_vendor_url_bug = _java_vendor_url_bug;
       // save it in _java_vendor_url_bug, so JVM fatal error handler can access
       // its value without going through the property list or making a Java call.
       _java_vendor_url_bug = os::strdup_check_oom(value, mtArguments);
-      if (old_java_vendor_url_bug != DEFAULT_VENDOR_URL_BUG) {
-        assert(old_java_vendor_url_bug != NULL, "_java_vendor_url_bug is NULL");
+      if (old_java_vendor_url_bug != NULL) {
         os::free((void *)old_java_vendor_url_bug);
       }
     }
@@ -2185,7 +2183,8 @@
 
 // Parse JavaVMInitArgs structure
 
-jint Arguments::parse_vm_init_args(const JavaVMInitArgs *java_tool_options_args,
+jint Arguments::parse_vm_init_args(const JavaVMInitArgs *vm_options_args,
+                                   const JavaVMInitArgs *java_tool_options_args,
                                    const JavaVMInitArgs *java_options_args,
                                    const JavaVMInitArgs *cmd_line_args) {
   bool patch_mod_javabase = false;
@@ -2203,9 +2202,15 @@
   // Setup flags for mixed which is the default
   set_mode_flags(_mixed);
 
+  // Parse args structure generated from java.base vm options resource
+  jint result = parse_each_vm_init_arg(vm_options_args, &patch_mod_javabase, JVMFlag::JIMAGE_RESOURCE);
+  if (result != JNI_OK) {
+    return result;
+  }
+
   // Parse args structure generated from JAVA_TOOL_OPTIONS environment
   // variable (if present).
-  jint result = parse_each_vm_init_arg(java_tool_options_args, &patch_mod_javabase, JVMFlag::ENVIRON_VAR);
+  result = parse_each_vm_init_arg(java_tool_options_args, &patch_mod_javabase, JVMFlag::ENVIRON_VAR);
   if (result != JNI_OK) {
     return result;
   }
@@ -2711,7 +2716,6 @@
         needs_module_property_warning = true;
         continue;
       }
-
       if (!add_property(tail)) {
         return JNI_ENOMEM;
       }
@@ -3832,16 +3836,19 @@
   const char* hotspotrc = ".hotspotrc";
   bool settings_file_specified = false;
   bool needs_hotspotrc_warning = false;
+  ScopedVMInitArgs initial_vm_options_args("");
   ScopedVMInitArgs initial_java_tool_options_args("env_var='JAVA_TOOL_OPTIONS'");
   ScopedVMInitArgs initial_java_options_args("env_var='_JAVA_OPTIONS'");
 
   // Pointers to current working set of containers
   JavaVMInitArgs* cur_cmd_args;
+  JavaVMInitArgs* cur_vm_options_args;
   JavaVMInitArgs* cur_java_options_args;
   JavaVMInitArgs* cur_java_tool_options_args;
 
   // Containers for modified/expanded options
   ScopedVMInitArgs mod_cmd_args("cmd_line_args");
+  ScopedVMInitArgs mod_vm_options_args("vm_options_args");
   ScopedVMInitArgs mod_java_tool_options_args("env_var='JAVA_TOOL_OPTIONS'");
   ScopedVMInitArgs mod_java_options_args("env_var='_JAVA_OPTIONS'");
 
@@ -3857,6 +3864,16 @@
     return code;
   }
 
+  // Parse the options in the /java.base/jdk/internal/vm/options resource, if present
+  char *vmoptions = ClassLoader::lookup_vm_options();
+  if (vmoptions != NULL) {
+    code = parse_options_buffer("vm options resource", vmoptions, strlen(vmoptions), &initial_vm_options_args);
+    FREE_C_HEAP_ARRAY(char, vmoptions);
+    if (code != JNI_OK) {
+      return code;
+    }
+  }
+
   code = expand_vm_options_as_needed(initial_java_tool_options_args.get(),
                                      &mod_java_tool_options_args,
                                      &cur_java_tool_options_args);
@@ -3878,6 +3895,13 @@
     return code;
   }
 
+  code = expand_vm_options_as_needed(initial_vm_options_args.get(),
+                                     &mod_vm_options_args,
+                                     &cur_vm_options_args);
+  if (code != JNI_OK) {
+    return code;
+  }
+
   const char* flags_file = Arguments::get_jvm_flags_file();
   settings_file_specified = (flags_file != NULL);
 
@@ -3915,7 +3939,8 @@
   }
 
   // Parse JavaVMInitArgs structure passed in, as well as JAVA_TOOL_OPTIONS and _JAVA_OPTIONS
-  jint result = parse_vm_init_args(cur_java_tool_options_args,
+  jint result = parse_vm_init_args(cur_vm_options_args,
+                                   cur_java_tool_options_args,
                                    cur_java_options_args,
                                    cur_cmd_args);
 
--- a/src/hotspot/share/runtime/arguments.hpp	Tue Oct 29 11:33:25 2019 +0100
+++ b/src/hotspot/share/runtime/arguments.hpp	Tue Oct 29 08:26:55 2019 -0700
@@ -427,7 +427,8 @@
 
   static void handle_extra_cms_flags(const char* msg);
 
-  static jint parse_vm_init_args(const JavaVMInitArgs *java_tool_options_args,
+  static jint parse_vm_init_args(const JavaVMInitArgs *vm_options_args,
+                                 const JavaVMInitArgs *java_tool_options_args,
                                  const JavaVMInitArgs *java_options_args,
                                  const JavaVMInitArgs *cmd_line_args);
   static jint parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_mod_javabase, JVMFlag::Flags origin);
--- a/src/hotspot/share/runtime/flags/jvmFlag.cpp	Tue Oct 29 11:33:25 2019 +0100
+++ b/src/hotspot/share/runtime/flags/jvmFlag.cpp	Tue Oct 29 08:26:55 2019 -0700
@@ -709,6 +709,8 @@
       st->print("attach"); break;
     case INTERNAL:
       st->print("internal"); break;
+    case JIMAGE_RESOURCE:
+      st->print("jimage"); break;
   }
   st->print("}");
 }
--- a/src/hotspot/share/runtime/flags/jvmFlag.hpp	Tue Oct 29 11:33:25 2019 +0100
+++ b/src/hotspot/share/runtime/flags/jvmFlag.hpp	Tue Oct 29 08:26:55 2019 -0700
@@ -44,8 +44,9 @@
     ERGONOMIC        = 5,
     ATTACH_ON_DEMAND = 6,
     INTERNAL         = 7,
+    JIMAGE_RESOURCE  = 8,
 
-    LAST_VALUE_ORIGIN = INTERNAL,
+    LAST_VALUE_ORIGIN = JIMAGE_RESOURCE,
     VALUE_ORIGIN_BITS = 4,
     VALUE_ORIGIN_MASK = right_n_bits(VALUE_ORIGIN_BITS),
 
--- a/src/hotspot/share/runtime/java.cpp	Tue Oct 29 11:33:25 2019 +0100
+++ b/src/hotspot/share/runtime/java.cpp	Tue Oct 29 08:26:55 2019 -0700
@@ -690,6 +690,8 @@
 JDK_Version JDK_Version::_current;
 const char* JDK_Version::_runtime_name;
 const char* JDK_Version::_runtime_version;
+const char* JDK_Version::_runtime_vendor_version;
+const char* JDK_Version::_runtime_vendor_vm_bug_url;
 
 void JDK_Version::initialize() {
   jdk_version_info info;
--- a/src/hotspot/share/runtime/java.hpp	Tue Oct 29 11:33:25 2019 +0100
+++ b/src/hotspot/share/runtime/java.hpp	Tue Oct 29 08:26:55 2019 -0700
@@ -67,6 +67,8 @@
   static JDK_Version _current;
   static const char* _runtime_name;
   static const char* _runtime_version;
+  static const char* _runtime_vendor_version;
+  static const char* _runtime_vendor_vm_bug_url;
 
   uint8_t _major;
   uint8_t _minor;
@@ -142,6 +144,20 @@
     _runtime_version = version;
   }
 
+  static const char* runtime_vendor_version() {
+    return _runtime_vendor_version;
+  }
+  static void set_runtime_vendor_version(const char* vendor_version) {
+    _runtime_vendor_version = vendor_version;
+  }
+
+  static const char* runtime_vendor_vm_bug_url() {
+    return _runtime_vendor_vm_bug_url;
+  }
+  static void set_runtime_vendor_vm_bug_url(const char* vendor_vm_bug_url) {
+    _runtime_vendor_vm_bug_url = vendor_vm_bug_url;
+  }
+
 };
 
 #endif // SHARE_RUNTIME_JAVA_HPP
--- a/src/hotspot/share/runtime/thread.cpp	Tue Oct 29 11:33:25 2019 +0100
+++ b/src/hotspot/share/runtime/thread.cpp	Tue Oct 29 08:26:55 2019 -0700
@@ -1090,6 +1090,8 @@
 
 char java_runtime_name[128] = "";
 char java_runtime_version[128] = "";
+char java_runtime_vendor_version[128] = "";
+char java_runtime_vendor_vm_bug_url[128] = "";
 
 // extract the JRE name from java.lang.VersionProps.java_runtime_name
 static const char* get_java_runtime_name(TRAPS) {
@@ -1135,6 +1137,50 @@
   }
 }
 
+// extract the JRE vendor version from java.lang.VersionProps.VENDOR_VERSION
+static const char* get_java_runtime_vendor_version(TRAPS) {
+  Klass* k = SystemDictionary::find(vmSymbols::java_lang_VersionProps(),
+                                    Handle(), Handle(), CHECK_AND_CLEAR_NULL);
+  fieldDescriptor fd;
+  bool found = k != NULL &&
+               InstanceKlass::cast(k)->find_local_field(vmSymbols::java_runtime_vendor_version_name(),
+                                                        vmSymbols::string_signature(), &fd);
+  if (found) {
+    oop name_oop = k->java_mirror()->obj_field(fd.offset());
+    if (name_oop == NULL) {
+      return NULL;
+    }
+    const char* name = java_lang_String::as_utf8_string(name_oop,
+                                                        java_runtime_vendor_version,
+                                                        sizeof(java_runtime_vendor_version));
+    return name;
+  } else {
+    return NULL;
+  }
+}
+
+// extract the JRE vendor VM bug URL from java.lang.VersionProps.VENDOR_URL_VM_BUG
+static const char* get_java_runtime_vendor_vm_bug_url(TRAPS) {
+  Klass* k = SystemDictionary::find(vmSymbols::java_lang_VersionProps(),
+                                    Handle(), Handle(), CHECK_AND_CLEAR_NULL);
+  fieldDescriptor fd;
+  bool found = k != NULL &&
+               InstanceKlass::cast(k)->find_local_field(vmSymbols::java_runtime_vendor_vm_bug_url_name(),
+                                                        vmSymbols::string_signature(), &fd);
+  if (found) {
+    oop name_oop = k->java_mirror()->obj_field(fd.offset());
+    if (name_oop == NULL) {
+      return NULL;
+    }
+    const char* name = java_lang_String::as_utf8_string(name_oop,
+                                                        java_runtime_vendor_vm_bug_url,
+                                                        sizeof(java_runtime_vendor_vm_bug_url));
+    return name;
+  } else {
+    return NULL;
+  }
+}
+
 // General purpose hook into Java code, run once when the VM is initialized.
 // The Java library method itself may be changed independently from the VM.
 static void call_postVMInitHook(TRAPS) {
@@ -3656,9 +3702,11 @@
   // Phase 1 of the system initialization in the library, java.lang.System class initialization
   call_initPhase1(CHECK);
 
-  // get the Java runtime name after java.lang.System is initialized
+  // get the Java runtime name, version, and vendor info after java.lang.System is initialized
   JDK_Version::set_runtime_name(get_java_runtime_name(THREAD));
   JDK_Version::set_runtime_version(get_java_runtime_version(THREAD));
+  JDK_Version::set_runtime_vendor_version(get_java_runtime_vendor_version(THREAD));
+  JDK_Version::set_runtime_vendor_vm_bug_url(get_java_runtime_vendor_vm_bug_url(THREAD));
 
   // an instance of OutOfMemory exception has been allocated earlier
   initialize_class(vmSymbols::java_lang_OutOfMemoryError(), CHECK);
--- a/src/hotspot/share/runtime/vmStructs.cpp	Tue Oct 29 11:33:25 2019 +0100
+++ b/src/hotspot/share/runtime/vmStructs.cpp	Tue Oct 29 08:26:55 2019 -0700
@@ -2612,6 +2612,7 @@
   declare_constant(JVMFlag::ERGONOMIC)                                    \
   declare_constant(JVMFlag::ATTACH_ON_DEMAND)                             \
   declare_constant(JVMFlag::INTERNAL)                                     \
+  declare_constant(JVMFlag::JIMAGE_RESOURCE)                              \
   declare_constant(JVMFlag::VALUE_ORIGIN_MASK)                            \
   declare_constant(JVMFlag::ORIG_COMMAND_LINE)
 
--- a/src/hotspot/share/utilities/vmError.cpp	Tue Oct 29 11:33:25 2019 +0100
+++ b/src/hotspot/share/utilities/vmError.cpp	Tue Oct 29 08:26:55 2019 -0700
@@ -130,7 +130,10 @@
   if (out == NULL) return;
   out->print_raw_cr("# If you would like to submit a bug report, please visit:");
   out->print_raw   ("#   ");
-  out->print_raw_cr(Arguments::java_vendor_url_bug());
+  const char *url = Arguments::java_vendor_url_bug();
+  if (url == NULL || *url == '\0')
+    url = JDK_Version::runtime_vendor_vm_bug_url();
+  out->print_raw_cr(url);
   // If the crash is in native code, encourage user to submit a bug to the
   // provider of that code.
   if (thread && thread->is_Java_thread() &&
@@ -321,15 +324,19 @@
                                 JDK_Version::runtime_name() : "";
    const char* runtime_version = JDK_Version::runtime_version() != NULL ?
                                    JDK_Version::runtime_version() : "";
+   const char* vendor_version = JDK_Version::runtime_vendor_version() != NULL ?
+                                  JDK_Version::runtime_vendor_version() : "";
    const char* jdk_debug_level = VM_Version::printable_jdk_debug_level() != NULL ?
                                    VM_Version::printable_jdk_debug_level() : "";
 
-   st->print_cr("# JRE version: %s (%s) (%sbuild %s)", runtime_name, buf,
-                 jdk_debug_level, runtime_version);
+   st->print_cr("# JRE version: %s%s%s (%s) (%sbuild %s)", runtime_name,
+                (*vendor_version != '\0') ? " " : "", vendor_version,
+                buf, jdk_debug_level, runtime_version);
 
    // This is the long version with some default settings added
-   st->print_cr("# Java VM: %s (%s%s, %s%s%s%s%s, %s, %s)",
+   st->print_cr("# Java VM: %s%s%s (%s%s, %s%s%s%s%s, %s, %s)",
                  VM_Version::vm_name(),
+                (*vendor_version != '\0') ? " " : "", vendor_version,
                  jdk_debug_level,
                  VM_Version::vm_release(),
                  VM_Version::vm_info_string(),
--- a/src/java.base/share/classes/java/lang/VersionProps.java.template	Tue Oct 29 11:33:25 2019 +0100
+++ b/src/java.base/share/classes/java/lang/VersionProps.java.template	Tue Oct 29 08:26:55 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2019, 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
@@ -42,9 +42,11 @@
     private static final String java_version_date =
         "@@VERSION_DATE@@";
 
+    // This field is read by HotSpot
     private static final String java_runtime_name =
         "@@RUNTIME_NAME@@";
 
+    // This field is read by HotSpot
     private static final String java_runtime_version =
         "@@VERSION_STRING@@";
 
@@ -69,22 +71,26 @@
     private static final String CLASSFILE_MAJOR_MINOR =
         "@@VERSION_CLASSFILE_MAJOR@@.@@VERSION_CLASSFILE_MINOR@@";
 
-    private static final String VENDOR_VERSION_STRING =
-        "@@VENDOR_VERSION_STRING@@";
-
-    private static final String vendor_version =
-        (!VENDOR_VERSION_STRING.isEmpty()
-         ? " " + VENDOR_VERSION_STRING : "");
-
     private static final String VENDOR =
         "@@VENDOR@@";
 
     private static final String VENDOR_URL =
         "@@VENDOR_URL@@";
 
-    private static final String VENDOR_URL_BUG =
+    // The remaining VENDOR_* fields must not be final,
+    // so that they can be redefined by jlink plugins
+
+    // This field is read by HotSpot
+    private static String VENDOR_VERSION =
+        "@@VENDOR_VERSION_STRING@@";
+
+    private static String VENDOR_URL_BUG =
         "@@VENDOR_URL_BUG@@";
 
+    // This field is read by HotSpot
+    private static String VENDOR_URL_VM_BUG =
+        "@@VENDOR_URL_VM_BUG@@";
+
     /**
      * Initialize system properties using build provided values.
      *
@@ -95,8 +101,8 @@
         props.put("java.version.date", java_version_date);
         props.put("java.runtime.version", java_runtime_version);
         props.put("java.runtime.name", java_runtime_name);
-        if (!VENDOR_VERSION_STRING.isEmpty())
-            props.put("java.vendor.version", VENDOR_VERSION_STRING);
+        if (!VENDOR_VERSION.isEmpty())
+            props.put("java.vendor.version", VENDOR_VERSION);
 
         props.put("java.class.version", CLASSFILE_MAJOR_MINOR);
 
@@ -216,6 +222,9 @@
             jdk_debug_level = jdk_debug_level + " ";
         }
 
+        String vendor_version = (VENDOR_VERSION.isEmpty()
+                                 ? "" : " " + VENDOR_VERSION);
+
         ps.println(java_runtime_name + vendor_version
                    + " (" + jdk_debug_level + "build " + java_runtime_version + ")");
 
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Flags.java	Tue Oct 29 11:33:25 2019 +0100
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Flags.java	Tue Oct 29 08:26:55 2019 -0700
@@ -35,7 +35,8 @@
   MANAGEMENT ("Management"),
   ERGONOMIC ("Ergonomic"),
   ATTACH_ON_DEMAND ("Attach on demand"),
-  INTERNAL ("Internal");
+  INTERNAL ("Internal"),
+  JIMAGE_RESOURCE ("JImage");
 
   private final String value;
 
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java	Tue Oct 29 11:33:25 2019 +0100
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java	Tue Oct 29 08:26:55 2019 -0700
@@ -114,6 +114,7 @@
   public static int    Flags_ERGONOMIC;
   public static int    Flags_ATTACH_ON_DEMAND;
   public static int    Flags_INTERNAL;
+  public static int    Flags_JIMAGE_RESOURCE;
   private static int   Flags_VALUE_ORIGIN_MASK;
   private static int   Flags_ORIG_COMMAND_LINE;
   /** This is only present in a non-core build */
@@ -200,6 +201,8 @@
             return "attach";
         } else if (origin == Flags_INTERNAL) {
             return "internal";
+        } else if (origin == Flags_JIMAGE_RESOURCE) {
+            return "jimage";
         } else {
             throw new IllegalStateException(
                 "Unknown flag origin " + origin + " is detected in " + name);
@@ -484,6 +487,7 @@
     Flags_ERGONOMIC = db.lookupIntConstant("JVMFlag::ERGONOMIC").intValue();
     Flags_ATTACH_ON_DEMAND = db.lookupIntConstant("JVMFlag::ATTACH_ON_DEMAND").intValue();
     Flags_INTERNAL = db.lookupIntConstant("JVMFlag::INTERNAL").intValue();
+    Flags_JIMAGE_RESOURCE = db.lookupIntConstant("JVMFlag::JIMAGE_RESOURCE").intValue();
     Flags_VALUE_ORIGIN_MASK = db.lookupIntConstant("JVMFlag::VALUE_ORIGIN_MASK").intValue();
     Flags_ORIG_COMMAND_LINE = db.lookupIntConstant("JVMFlag::ORIG_COMMAND_LINE").intValue();
     oopSize  = db.lookupIntConstant("oopSize").intValue();
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginConfiguration.java	Tue Oct 29 11:33:25 2019 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginConfiguration.java	Tue Oct 29 08:26:55 2019 -0700
@@ -50,6 +50,7 @@
 
     static {
         CATEGORIES_ORDER.add(Category.FILTER);
+        CATEGORIES_ORDER.add(Category.ADDER);
         CATEGORIES_ORDER.add(Category.TRANSFORMER);
         CATEGORIES_ORDER.add(Category.MODULEINFO_TRANSFORMER);
         CATEGORIES_ORDER.add(Category.SORTER);
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java	Tue Oct 29 11:33:25 2019 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java	Tue Oct 29 08:26:55 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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
@@ -325,7 +325,7 @@
 
                                 Map<String, String> m = addArgumentMap(plugin);
                                 // handle one or more arguments
-                                if (arg.indexOf(':') == -1) {
+                                if (plugin.hasRawArgument() || arg.indexOf(':') == -1) {
                                     // single argument case
                                     m.put(option, arg);
                                 } else {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/AddOptionsPlugin.java	Tue Oct 29 08:26:55 2019 -0700
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2019, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 jdk.tools.jlink.internal.plugins;
+
+import java.io.*;
+import java.nio.charset.*;
+import java.util.*;
+import java.util.function.*;
+import java.util.stream.*;
+import jdk.tools.jlink.plugin.*;
+
+/**
+ * Plugin to add VM command-line options, by storing them in a resource
+ * that's read by the VM at startup
+ */
+public final class AddOptionsPlugin extends AddResourcePlugin {
+
+    public AddOptionsPlugin() {
+        super("add-options", "/java.base/jdk/internal/vm/options");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/AddResourcePlugin.java	Tue Oct 29 08:26:55 2019 -0700
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2019, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 jdk.tools.jlink.internal.plugins;
+
+import java.io.*;
+import java.nio.charset.*;
+import java.util.*;
+import java.util.function.*;
+import java.util.stream.*;
+import jdk.tools.jlink.plugin.*;
+
+/**
+ * Base plugin to add a resource
+ */
+abstract class AddResourcePlugin implements Plugin {
+
+    private final String name;
+    private final String path;
+    private String value;
+
+    protected AddResourcePlugin(String n, String p) {
+        name = n;
+        path = p;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public String getDescription() {
+        return PluginsResourceBundle.getDescription(name);
+    }
+
+    @Override
+    public Category getType() {
+        return Category.ADDER;
+    }
+
+    @Override
+    public boolean hasArguments() {
+        return true;
+    }
+
+    @Override
+    public boolean hasRawArgument() {
+        return true;
+    }
+
+    @Override
+    public String getArgumentsDescription() {
+       return PluginsResourceBundle.getArgument(name);
+    }
+
+    @Override
+    public void configure(Map<String, String> config) {
+        var v = config.get(name);
+        if (v == null)
+            throw new AssertionError();
+        value = v;
+    }
+
+    @Override
+    public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) {
+        in.transformAndCopy(Function.identity(), out);
+        out.add(ResourcePoolEntry.create(path,
+                                         value.getBytes(StandardCharsets.UTF_8)));
+        return out.build();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/VendorBugURLPlugin.java	Tue Oct 29 08:26:55 2019 -0700
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2019, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 jdk.tools.jlink.internal.plugins;
+
+/**
+ * Plugin to set the vendor bug URL, by redefining the static field
+ * java.lang.VersionProps.VENDOR_URL_BUG
+ */
+public final class VendorBugURLPlugin extends VersionPropsPlugin {
+
+    public VendorBugURLPlugin() {
+        super("VENDOR_URL_BUG", "vendor-bug-url");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/VendorVMBugURLPlugin.java	Tue Oct 29 08:26:55 2019 -0700
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2019, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 jdk.tools.jlink.internal.plugins;
+
+/**
+ * Plugin to set the vendor VM bug URL, by redefining the static field
+ * java.lang.VersionProps.VENDOR_URL_VM_BUG
+ */
+public final class VendorVMBugURLPlugin extends VersionPropsPlugin {
+
+    public VendorVMBugURLPlugin() {
+        super("VENDOR_URL_VM_BUG", "vendor-vm-bug-url");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/VendorVersionPlugin.java	Tue Oct 29 08:26:55 2019 -0700
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2019, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 jdk.tools.jlink.internal.plugins;
+
+/**
+ * Plugin to set the vendor version string, by redefining the static field
+ * java.lang.VersionProps.VENDOR_VERSION
+ */
+public final class VendorVersionPlugin extends VersionPropsPlugin {
+
+    public VendorVersionPlugin() {
+        super("VENDOR_VERSION");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/VersionPropsPlugin.java	Tue Oct 29 08:26:55 2019 -0700
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2019, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 jdk.tools.jlink.internal.plugins;
+
+import java.io.*;
+import java.nio.charset.*;
+import java.util.*;
+import java.util.function.*;
+import java.util.stream.*;
+import jdk.tools.jlink.plugin.*;
+import jdk.internal.org.objectweb.asm.*;
+
+import static java.lang.System.out;
+
+/**
+ * Base plugin to update a static field in java.lang.VersionProps
+ */
+abstract class VersionPropsPlugin implements Plugin {
+
+    private static final String VERSION_PROPS_CLASS
+        = "/java.base/java/lang/VersionProps.class";
+
+    private final String name;
+    private final String field;
+    private String value;
+
+    /**
+     * @param field The name of the java.lang.VersionProps field to be redefined
+     * @param option The option name
+     */
+    protected VersionPropsPlugin(String field, String option) {
+        this.field = field;
+        this.name = option;
+    }
+
+    /**
+     * Shorthand constructor for when the option name can be derived from the
+     * name of the field.
+     *
+     * @param field The name of the java.lang.VersionProps field to be redefined
+     */
+    protected VersionPropsPlugin(String field) {
+        this(field, field.toLowerCase().replace('_', '-'));
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public String getDescription() {
+        return PluginsResourceBundle.getDescription(name);
+    }
+
+    @Override
+    public Category getType() {
+        return Category.TRANSFORMER;
+    }
+
+    @Override
+    public boolean hasArguments() {
+        return true;
+    }
+
+    @Override
+    public boolean hasRawArgument() {
+        return true;
+    }
+
+    @Override
+    public String getArgumentsDescription() {
+       return PluginsResourceBundle.getArgument(name);
+    }
+
+    @Override
+    public void configure(Map<String, String> config) {
+        var v = config.get(name);
+        if (v == null)
+            throw new AssertionError();
+        value = v;
+    }
+
+    private boolean redefined = false;
+
+    private byte[] redefine(byte[] classFile) {
+
+        var cr = new ClassReader(classFile);
+        var cw = new ClassWriter(0);
+
+        cr.accept(new ClassVisitor(Opcodes.ASM7, cw) {
+
+                public MethodVisitor visitMethod(int access,
+                                                 String name,
+                                                 String desc,
+                                                 String sig,
+                                                 String[] xs)
+                {
+                    if (name.equals("<clinit>"))
+                        return new MethodVisitor(Opcodes.ASM7,
+                                                 super.visitMethod(access,
+                                                                   name,
+                                                                   desc,
+                                                                   sig,
+                                                                   xs))
+                            {
+
+                                public void visitFieldInsn(int opcode,
+                                                           String owner,
+                                                           String name,
+                                                           String desc)
+                                {
+                                    if (opcode == Opcodes.PUTSTATIC
+                                        && name.equals(field))
+                                    {
+                                        // Discard the original value
+                                        super.visitInsn(Opcodes.POP);
+                                        // Load the value that we want
+                                        super.visitLdcInsn(value);
+                                        redefined = true;
+                                    }
+                                    super.visitFieldInsn(opcode, owner,
+                                                         name, desc);
+                                }
+
+                        };
+                    else
+                        return super.visitMethod(access, name, desc, sig, xs);
+                }
+
+            }, 0);
+
+        return cw.toByteArray();
+
+    }
+
+    @Override
+    public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) {
+        in.transformAndCopy(res -> {
+                if (res.type().equals(ResourcePoolEntry.Type.CLASS_OR_RESOURCE)) {
+                    if (res.path().equals(VERSION_PROPS_CLASS)) {
+                        return res.copyWithContent(redefine(res.contentBytes()));
+                    }
+                }
+                return res;
+            }, out);
+        if (!redefined)
+            throw new AssertionError(field);
+        return out.build();
+    }
+
+}
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/Plugin.java	Tue Oct 29 11:33:25 2019 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/Plugin.java	Tue Oct 29 08:26:55 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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
@@ -39,6 +39,7 @@
      * Order of categories matches the plugin sort order.
      * <ol>
      * <li>FILTER: Filter in/out resources or files.</li>
+     * <li>ADDER: Add resources or files.</li>
      * <li>TRANSFORMER: Transform resources or files(eg: refactoring, bytecode
      * manipulation).</li>
      * <li>MODULEINFO_TRANSFORMER: Transform only module-info.class</li>
@@ -52,6 +53,7 @@
      */
     public enum Category {
         FILTER("FILTER"),
+        ADDER("ADDER"),
         TRANSFORMER("TRANSFORMER"),
         MODULEINFO_TRANSFORMER("MODULEINFO_TRANSFORMER"),
         SORTER("SORTER"),
@@ -152,6 +154,10 @@
         return false;
     }
 
+    public default boolean hasRawArgument() {
+        return false;
+    }
+
     /**
      * The plugin argument(s) description.
      * @return  The argument(s) description.
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties	Tue Oct 29 11:33:25 2019 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties	Tue Oct 29 08:26:55 2019 -0700
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2015, 2019, 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
@@ -23,6 +23,13 @@
 # questions.
 #
 
+add-options.argument=<options>
+
+add-options.description=\
+Prepend the specified <options> string, which may include\n\
+whitespace, before any other options when invoking the virtual machine\n\
+in the resulting image.
+
 release-info.argument=<file>|add:<key1>=<value1>:<key2>=<value2>:...|del:<key list>
 
 release-info.description=\
@@ -105,6 +112,24 @@
 strip-native-commands.description=\
 Exclude native commands (such as java/java.exe) from the image
 
+vendor-version.argument=<vendor-version>
+
+vendor-version.description=\
+Override the vendor version string baked into the build, if any.\n\
+The value of the system property "java.vendor.version" will be <vendor-version>.
+
+vendor-bug-url.argument=<vendor-bug-url>
+
+vendor-bug-url.description=\
+Override the vendor bug URL baked into the build.  The value\n\
+of the system property "java.vendor.url.bug" will be <vendor-url-bug>.
+
+vendor-vm-bug-url.argument=<vendor-vm-bug-url>
+
+vendor-vm-bug-url.description=\
+Override the vendor VM bug URL baked into the build.  The URL\n\
+displayed in VM error logs will be <vendor-vm-bug-url>.
+
 vm.argument=<client|server|minimal|all>
 
 vm.description=\
--- a/src/jdk.jlink/share/classes/module-info.java	Tue Oct 29 11:33:25 2019 +0100
+++ b/src/jdk.jlink/share/classes/module-info.java	Tue Oct 29 08:26:55 2019 -0700
@@ -72,5 +72,10 @@
         jdk.tools.jlink.internal.plugins.ExcludeVMPlugin,
         jdk.tools.jlink.internal.plugins.IncludeLocalesPlugin,
         jdk.tools.jlink.internal.plugins.GenerateJLIClassesPlugin,
-        jdk.tools.jlink.internal.plugins.ReleaseInfoPlugin;
- }
+        jdk.tools.jlink.internal.plugins.ReleaseInfoPlugin,
+        jdk.tools.jlink.internal.plugins.AddOptionsPlugin,
+        jdk.tools.jlink.internal.plugins.VendorBugURLPlugin,
+        jdk.tools.jlink.internal.plugins.VendorVMBugURLPlugin,
+        jdk.tools.jlink.internal.plugins.VendorVersionPlugin;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/tools/jlink/plugins/AddOptionsPluginTest.java	Tue Oct 29 08:26:55 2019 -0700
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2019, 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 jdk.test.lib.process.*;
+
+import tests.Helper;
+
+/* @test
+ * @bug 8232080
+ * @summary Test the --add-options plugin
+ * @library ../../lib
+ * @library /test/lib
+ * @modules java.base/jdk.internal.jimage
+ *          jdk.jdeps/com.sun.tools.classfile
+ *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jmod
+ *          jdk.jlink/jdk.tools.jimage
+ *          jdk.compiler
+ * @build tests.*
+ * @run main AddOptionsPluginTest
+ */
+
+public class AddOptionsPluginTest {
+
+    private static final String PROP = "add.options.plugin.test";
+    private static final String VALUE = "xyzzy";
+    private static final String OPTS = "-D" + PROP + "=" + VALUE;
+
+    public static void main(String[] args) throws Throwable {
+
+        Helper helper = Helper.newHelper();
+        if (helper == null) {
+            System.err.println("Test not run");
+            return;
+        }
+
+        var module = "addoptions";
+        helper.generateDefaultJModule(module);
+        var image = helper.generateDefaultImage(new String[] { "--add-options", OPTS },
+                                                module)
+            .assertSuccess();
+        helper.checkImage(image, module, null, null);
+
+        var launcher = image.resolve("bin/java"
+                                     + (System.getProperty("os.name").startsWith("Windows")
+                                        ? ".exe" : ""));
+        var oa = ProcessTools.executeProcess(launcher.toString(),
+                                             "-XshowSettings:properties", "--version");
+        oa.stderrShouldMatch("^ +" + PROP + " = " + VALUE + "$");
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/tools/jlink/plugins/VendorInfoPluginsTest.java	Tue Oct 29 08:26:55 2019 -0700
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2019, 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 jdk.test.lib.process.*;
+
+import tests.Helper;
+
+/* @test
+ * @bug 8232080
+ * @summary Test the --vendor-version --vendor-url-bug plugins
+ * @library ../../lib
+ * @library /test/lib
+ * @modules java.base/jdk.internal.jimage
+ *          jdk.jdeps/com.sun.tools.classfile
+ *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jmod
+ *          jdk.jlink/jdk.tools.jimage
+ *          jdk.compiler
+ * @build tests.*
+ * @run main VendorInfoPluginsTest
+ */
+
+public class VendorInfoPluginsTest {
+
+    public static class Crasher {
+
+        public static void main(String ... args) throws Exception {
+            var uc = Class.forName("sun.misc.Unsafe");
+            var f = uc.getDeclaredField("theUnsafe");
+            f.setAccessible(true);
+            var u = (sun.misc.Unsafe)f.get(null);
+            for (long a = 0; a < Long.MAX_VALUE; a += 8)
+                u.putLong(a, -1L);
+        }
+
+    }
+
+    private static final String VERSION = "XyzzyVM 3.14.15";
+    private static final String BUG_URL = "https://bugs.xyzzy.com/";
+    private static final String VM_BUG_URL = "https://bugs.xyzzy.com/crash/";
+
+    public static void main(String[] args) throws Throwable {
+
+        Helper helper = Helper.newHelper();
+        if (helper == null) {
+            System.err.println("Test not run");
+            return;
+        }
+
+        var module = "vendorinfo";
+        helper.generateDefaultJModule(module);
+        var image = helper.generateDefaultImage(new String[] {
+                "--add-modules", "jdk.unsupported",
+                "--vendor-version", VERSION,
+                "--vendor-bug-url", BUG_URL,
+                "--vendor-vm-bug-url", VM_BUG_URL },
+            module).assertSuccess();
+        helper.checkImage(image, module, null, null);
+
+        // Properties and --version
+        var launcher
+            = image.resolve("bin/java"
+                            + (System.getProperty("os.name").startsWith("Windows")
+                               ? ".exe" : "")).toString();
+        var oa = ProcessTools.executeProcess(launcher,
+                                             "-XshowSettings:properties",
+                                             "--version");
+        oa.stderrShouldMatch("^ +java.vendor.url.bug = " + BUG_URL + "$");
+        oa.stderrShouldMatch("^ +java.vendor.version = " + VERSION + "$");
+        oa.stdoutShouldMatch("^.*Runtime Environment " + VERSION + " \\(build.*$");
+        oa.stdoutShouldMatch("^.*Server VM " + VERSION + " \\(build.*$");
+
+        // VM error log
+        oa = ProcessTools.executeProcess(launcher,
+                                         "--class-path",
+                                         System.getProperty("test.classes"),
+                                         "VendorInfoPluginsTest$Crasher");
+        oa.stdoutShouldMatch("^# +" + VM_BUG_URL + "$");
+        oa.stdoutShouldMatch("^.*Runtime Environment " + VERSION + " \\(.*$");
+        oa.stdoutShouldMatch("^.*Server VM " + VERSION + " \\(.*$");
+
+    }
+
+}
--- a/test/lib/jdk/test/lib/cds/CDSTestUtils.java	Tue Oct 29 11:33:25 2019 +0100
+++ b/test/lib/jdk/test/lib/cds/CDSTestUtils.java	Tue Oct 29 08:26:55 2019 -0700
@@ -309,7 +309,7 @@
     // exceptions match. Pass null if you wish not to re-throw any exception.
     public static void checkCommonExecExceptions(OutputAnalyzer output, Exception e)
         throws Exception {
-        if (output.getStdout().contains("http://bugreport.java.com/bugreport/crash.jsp")) {
+        if (output.getStdout().contains("https://bugreport.java.com/bugreport/crash.jsp")) {
             throw new RuntimeException("Hotspot crashed");
         }
         if (output.getStdout().contains("TEST FAILED")) {