changeset 53360:58e25974ede4

Merge
author jwilhelm
date Wed, 16 Jan 2019 20:53:09 +0100
parents a47b8125b7cc cb4212fda8e4
children 4a59f7042325
files src/hotspot/share/code/codeHeapState.cpp src/hotspot/share/gc/g1/g1YoungRemSetSamplingThread.cpp src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m
diffstat 21 files changed, 670 insertions(+), 284 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/code/codeHeapState.cpp	Wed Jan 16 19:09:16 2019 +0000
+++ b/src/hotspot/share/code/codeHeapState.cpp	Wed Jan 16 20:53:09 2019 +0100
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2018 SAP SE. All rights reserved.
+ * Copyright (c) 2018, 2019 SAP SE. 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
@@ -40,15 +40,17 @@
 // contain enough detail to gain initial insight while keeping the
 // internal structure sizes in check.
 //
-// The CodeHeap is a living thing. Therefore, the aggregate is collected
-// under the CodeCache_lock. The subsequent print steps are only locked
-// against concurrent aggregations. That keeps the impact on
-// "normal operation" (JIT compiler and sweeper activity) to a minimum.
-//
 // The second part, which consists of several, independent steps,
 // prints the previously collected information with emphasis on
 // various aspects.
 //
+// The CodeHeap is a living thing. Therefore, protection against concurrent
+// modification (by acquiring the CodeCache_lock) is necessary. It has
+// to be provided by the caller of the analysis functions.
+// If the CodeCache_lock is not held, the analysis functions may print
+// less detailed information or may just do nothing. It is by intention
+// that an unprotected invocation is not abnormally terminated.
+//
 // Data collection and printing is done on an "on request" basis.
 // While no request is being processed, there is no impact on performance.
 // The CodeHeap state analytics do have some memory footprint.
@@ -456,7 +458,7 @@
   bool  done             = false;
   const int min_granules = 256;
   const int max_granules = 512*K; // limits analyzable CodeHeap (with segment_granules) to 32M..128M
-                                  // results in StatArray size of 20M (= max_granules * 40 Bytes per element)
+                                  // results in StatArray size of 24M (= max_granules * 48 Bytes per element)
                                   // For a 1GB CodeHeap, the granule size must be at least 2kB to not violate the max_granles limit.
   const char* heapName   = get_heapName(heap);
   STRINGSTREAM_DECL(ast, out)
@@ -495,6 +497,12 @@
     return;
   }
 
+  if (!CodeCache_lock->owned_by_self()) {
+    printBox(ast, '-', "aggregate function called without holding the CodeCache_lock for ", heapName);
+    STRINGSTREAM_FLUSH("")
+    return;
+  }
+
   // Calculate granularity of analysis (and output).
   //   The CodeHeap is managed (allocated) in segments (units) of CodeCacheSegmentSize.
   //   The CodeHeap can become fairly large, in particular in productive real-life systems.
@@ -1028,6 +1036,7 @@
       STRINGSTREAM_FLUSH("\n")
 
       // This loop is intentionally printing directly to "out".
+      // It should not print anything, anyway.
       out->print("Verifying collected data...");
       size_t granule_segs = granule_size>>log2_seg_size;
       for (unsigned int ix = 0; ix < granules; ix++) {
@@ -1071,6 +1080,7 @@
       }
 
       // This loop is intentionally printing directly to "out".
+      // It should not print anything, anyway.
       if (used_topSizeBlocks > 0) {
         unsigned int j = 0;
         if (TopSizeArray[0].len != currMax) {
@@ -1166,6 +1176,7 @@
   //---<  calculate and fill remaining fields  >---
   if (FreeArray != NULL) {
     // This loop is intentionally printing directly to "out".
+    // It should not print anything, anyway.
     for (unsigned int ix = 0; ix < alloc_freeBlocks-1; ix++) {
       size_t lenSum = 0;
       FreeArray[ix].gap = (unsigned int)((address)FreeArray[ix+1].start - ((address)FreeArray[ix].start + FreeArray[ix].len));
@@ -1223,6 +1234,7 @@
   //----------------------------
   {
     char*     low_bound = heap->low_boundary();
+    bool      have_CodeCache_lock = CodeCache_lock->owned_by_self();
 
     printBox(ast, '-', "Largest Used Blocks in ", heapName);
     print_blobType_legend(ast);
@@ -1241,12 +1253,19 @@
       unsigned int printed_topSizeBlocks = 0;
       for (unsigned int i = 0; i != tsbStopper; i = TopSizeArray[i].index) {
         printed_topSizeBlocks++;
-        CodeBlob*   this_blob = (CodeBlob*)(heap->find_start(TopSizeArray[i].start));
         nmethod*           nm = NULL;
-        const char* blob_name = "unnamed blob";
-        if (this_blob != NULL) {
-          blob_name = this_blob->name();
-          nm        = this_blob->as_nmethod_or_null();
+        const char* blob_name = "unnamed blob or blob name unavailable";
+        // heap->find_start() is safe. Only works on _segmap.
+        // Returns NULL or void*. Returned CodeBlob may be uninitialized.
+        HeapBlock* heapBlock = TopSizeArray[i].start;
+        CodeBlob*  this_blob = (CodeBlob*)(heap->find_start(heapBlock));
+        bool    blob_is_safe = blob_access_is_safe(this_blob, NULL);
+        if (blob_is_safe) {
+          //---<  access these fields only if we own the CodeCache_lock  >---
+          if (have_CodeCache_lock) {
+            blob_name = this_blob->name();
+            nm        = this_blob->as_nmethod_or_null();
+          }
           //---<  blob address  >---
           ast->print(INTPTR_FORMAT, p2i(this_blob));
           ast->fill_to(19);
@@ -1262,10 +1281,18 @@
           ast->fill_to(33);
         }
 
-
         //---<  print size, name, and signature (for nMethods)  >---
-        if ((nm != NULL) && (nm->method() != NULL)) {
+        // access nmethod and Method fields only if we own the CodeCache_lock.
+        // This fact is implicitly transported via nm != NULL.
+        if (CompiledMethod::nmethod_access_is_safe(nm)) {
           ResourceMark rm;
+          Method* method = nm->method();
+          if (nm->is_in_use()) {
+            blob_name = method->name_and_sig_as_C_string();
+          }
+          if (nm->is_not_entrant()) {
+            blob_name = method->name_and_sig_as_C_string();
+          }
           //---<  nMethod size in hex  >---
           unsigned int total_size = nm->total_size();
           ast->print(PTR32_FORMAT, total_size);
@@ -1280,10 +1307,12 @@
           ast->print("%5d", nm->hotness_counter());
           //---<  name and signature  >---
           ast->fill_to(67+6);
-          if (nm->is_in_use())        {blob_name = nm->method()->name_and_sig_as_C_string(); }
-          if (nm->is_not_entrant())   {blob_name = nm->method()->name_and_sig_as_C_string(); }
-          if (nm->is_not_installed()) {ast->print("%s", " not (yet) installed method "); }
-          if (nm->is_zombie())        {ast->print("%s", " zombie method "); }
+          if (nm->is_not_installed()) {
+            ast->print(" not (yet) installed method ");
+          }
+          if (nm->is_zombie()) {
+            ast->print(" zombie method ");
+          }
           ast->print("%s", blob_name);
         } else {
           //---<  block size in hex  >---
@@ -2083,10 +2112,11 @@
   }
   STRINGSTREAM_DECL(ast, out)
 
-  unsigned int granules_per_line  = 128;
-  char*        low_bound          = heap->low_boundary();
-  CodeBlob*    last_blob          = NULL;
-  bool         name_in_addr_range = true;
+  unsigned int granules_per_line   = 128;
+  char*        low_bound           = heap->low_boundary();
+  CodeBlob*    last_blob           = NULL;
+  bool         name_in_addr_range  = true;
+  bool         have_CodeCache_lock = CodeCache_lock->owned_by_self();
 
   //---<  print at least 128K per block (i.e. between headers)  >---
   if (granules_per_line*granule_size < 128*K) {
@@ -2121,16 +2151,14 @@
                            StatArray[ix].stub_count + StatArray[ix].dead_count;
     if (nBlobs > 0 ) {
     for (unsigned int is = 0; is < granule_size; is+=(unsigned int)seg_size) {
-      // heap->find_start() is safe. Only working with _segmap. Returns NULL or void*. Returned CodeBlob may be uninitialized.
-      CodeBlob* this_blob = (CodeBlob *)(heap->find_start(low_bound+ix*granule_size+is));
-      bool blob_initialized = (this_blob != NULL) && (this_blob->header_size() >= 0) && (this_blob->relocation_size() >= 0) &&
-                              ((address)this_blob + this_blob->header_size() == (address)(this_blob->relocation_begin())) &&
-                              ((address)this_blob + CodeBlob::align_code_offset(this_blob->header_size() + this_blob->relocation_size()) == (address)(this_blob->content_begin())) &&
-                              os::is_readable_pointer((address)(this_blob->relocation_begin())) &&
-                              os::is_readable_pointer(this_blob->content_begin());
+      // heap->find_start() is safe. Only works on _segmap.
+      // Returns NULL or void*. Returned CodeBlob may be uninitialized.
+      char*     this_seg  = low_bound + ix*granule_size + is;
+      CodeBlob* this_blob = (CodeBlob*)(heap->find_start(this_seg));
+      bool   blob_is_safe = blob_access_is_safe(this_blob, NULL);
       // blob could have been flushed, freed, and merged.
       // this_blob < last_blob is an indicator for that.
-      if (blob_initialized && (this_blob > last_blob)) {
+      if (blob_is_safe && (this_blob > last_blob)) {
         last_blob          = this_blob;
 
         //---<  get type and name  >---
@@ -2138,12 +2166,22 @@
         if (segment_granules) {
           cbType = (blobType)StatArray[ix].type;
         } else {
-          cbType = get_cbType(this_blob);
+          //---<  access these fields only if we own the CodeCache_lock  >---
+          if (have_CodeCache_lock) {
+            cbType = get_cbType(this_blob);
+          }
         }
-        // this_blob->name() could return NULL if no name was given to CTOR. Inlined, maybe invisible on stack
-        const char* blob_name = this_blob->name();
-        if ((blob_name == NULL) || !os::is_readable_pointer(blob_name)) {
-          blob_name = "<unavailable>";
+
+        //---<  access these fields only if we own the CodeCache_lock  >---
+        const char* blob_name = "<unavailable>";
+        nmethod*           nm = NULL;
+        if (have_CodeCache_lock) {
+          blob_name = this_blob->name();
+          nm        = this_blob->as_nmethod_or_null();
+          // this_blob->name() could return NULL if no name was given to CTOR. Inlined, maybe invisible on stack
+          if ((blob_name == NULL) || !os::is_readable_pointer(blob_name)) {
+            blob_name = "<unavailable>";
+          }
         }
 
         //---<  print table header for new print range  >---
@@ -2163,8 +2201,8 @@
         ast->print("(+" PTR32_FORMAT ")", (unsigned int)((char*)this_blob-low_bound));
         ast->fill_to(33);
 
-        // this_blob->as_nmethod_or_null() is safe. Inlined, maybe invisible on stack.
-        nmethod*    nm     = this_blob->as_nmethod_or_null();
+        // access nmethod and Method fields only if we own the CodeCache_lock.
+        // This fact is implicitly transported via nm != NULL.
         if (CompiledMethod::nmethod_access_is_safe(nm)) {
           Method* method = nm->method();
           ResourceMark rm;
@@ -2201,14 +2239,17 @@
           } else {
             ast->print("%s", blob_name);
           }
-        } else {
+        } else if (blob_is_safe) {
           ast->fill_to(62+6);
           ast->print("%s", blobTypeName[cbType]);
           ast->fill_to(82+6);
           ast->print("%s", blob_name);
+        } else {
+          ast->fill_to(62+6);
+          ast->print("<stale blob>");
         }
         STRINGSTREAM_FLUSH_LOCKED("\n")
-      } else if (!blob_initialized && (this_blob != last_blob) && (this_blob != NULL)) {
+      } else if (!blob_is_safe && (this_blob != last_blob) && (this_blob != NULL)) {
         last_blob          = this_blob;
         STRINGSTREAM_FLUSH_LOCKED("\n")
       }
@@ -2375,16 +2416,31 @@
     if (cb->is_method_handles_adapter_blob()) return mh_adapterBlob;
     if (cb->is_buffer_blob())                 return bufferBlob;
 
-    nmethod*  nm = cb->as_nmethod_or_null();
-    if (nm != NULL) { // no is_readable check required, nm = (nmethod*)cb.
-      if (nm->is_not_installed()) return nMethod_inconstruction;
-      if (nm->is_zombie())        return nMethod_dead;
-      if (nm->is_unloaded())      return nMethod_unloaded;
-      if (nm->is_in_use())        return nMethod_inuse;
-      if (nm->is_alive() && !(nm->is_not_entrant()))   return nMethod_notused;
-      if (nm->is_alive())         return nMethod_alive;
-      return nMethod_dead;
+    //---<  access these fields only if we own the CodeCache_lock  >---
+    // Should be ensured by caller. aggregate() amd print_names() do that.
+    if (CodeCache_lock->owned_by_self()) {
+      nmethod*  nm = cb->as_nmethod_or_null();
+      if (nm != NULL) { // no is_readable check required, nm = (nmethod*)cb.
+        if (nm->is_not_installed()) return nMethod_inconstruction;
+        if (nm->is_zombie())        return nMethod_dead;
+        if (nm->is_unloaded())      return nMethod_unloaded;
+        if (nm->is_in_use())        return nMethod_inuse;
+        if (nm->is_alive() && !(nm->is_not_entrant()))   return nMethod_notused;
+        if (nm->is_alive())         return nMethod_alive;
+        return nMethod_dead;
+      }
     }
   }
   return noType;
 }
+
+bool CodeHeapState::blob_access_is_safe(CodeBlob* this_blob, CodeBlob* prev_blob) {
+  return (this_blob != NULL) && // a blob must have been found, obviously
+         ((this_blob == prev_blob) || (prev_blob == NULL)) &&  // when re-checking, the same blob must have been found
+         (this_blob->header_size() >= 0) &&
+         (this_blob->relocation_size() >= 0) &&
+         ((address)this_blob + this_blob->header_size() == (address)(this_blob->relocation_begin())) &&
+         ((address)this_blob + CodeBlob::align_code_offset(this_blob->header_size() + this_blob->relocation_size()) == (address)(this_blob->content_begin())) &&
+         os::is_readable_pointer((address)(this_blob->relocation_begin())) &&
+         os::is_readable_pointer(this_blob->content_begin());
+}
--- a/src/hotspot/share/code/codeHeapState.hpp	Wed Jan 16 19:09:16 2019 +0000
+++ b/src/hotspot/share/code/codeHeapState.hpp	Wed Jan 16 20:53:09 2019 +0100
@@ -1,6 +1,6 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2018 SAP SE. All rights reserved.
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019 SAP SE. 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
@@ -95,6 +95,7 @@
   static void print_line_delim(outputStream* out, bufferedStream *sst, char* low_bound, unsigned int ix, unsigned int gpl);
   static void print_line_delim(outputStream* out, outputStream *sst, char* low_bound, unsigned int ix, unsigned int gpl);
   static blobType get_cbType(CodeBlob* cb);
+  static bool blob_access_is_safe(CodeBlob* this_blob, CodeBlob* prev_blob);
 
  public:
   static void discard(outputStream* out, CodeHeap* heap);
--- a/src/hotspot/share/compiler/compileBroker.cpp	Wed Jan 16 19:09:16 2019 +0000
+++ b/src/hotspot/share/compiler/compileBroker.cpp	Wed Jan 16 20:53:09 2019 +0100
@@ -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
@@ -2672,6 +2672,7 @@
 //       preventing concurrently printing threads from stalling a long time.
 void CompileBroker::print_heapinfo(outputStream* out, const char* function, const char* granularity) {
   TimeStamp ts_total;
+  TimeStamp ts_global;
   TimeStamp ts;
 
   bool allFun = !strcmp(function, "all");
@@ -2701,35 +2702,43 @@
   }
 
   // We hold the CodeHeapStateAnalytics_lock all the time, from here until we leave this function.
-  // That helps us getting a consistent view on the CodeHeap, at least for the "all" function.
+  // That prevents another thread from destroying our view on the CodeHeap.
   // When we request individual parts of the analysis via the jcmd interface, it is possible
   // that in between another thread (another jcmd user or the vm running into CodeCache OOM)
   // updated the aggregated data. That's a tolerable tradeoff because we can't hold a lock
   // across user interaction.
+  // Acquire this lock before acquiring the CodeCache_lock.
+  // CodeHeapStateAnalytics_lock could be held by a concurrent thread for a long time,
+  // leading to an unnecessarily long hold time of the CodeCache_lock.
   ts.update(); // record starting point
   MutexLockerEx mu1(CodeHeapStateAnalytics_lock, Mutex::_no_safepoint_check_flag);
-  out->cr();
-  out->print_cr("__ CodeHeapStateAnalytics lock wait took %10.3f seconds _________", ts.seconds());
-  out->cr();
+  out->print_cr("\n__ CodeHeapStateAnalytics lock wait took %10.3f seconds _________\n", ts.seconds());
+
+  // If we serve an "allFun" call, it is beneficial to hold the CodeCache_lock
+  // for the entire duration of aggregation and printing. That makes sure
+  // we see a consistent picture and do not run into issues caused by
+  // the CodeHeap being altered concurrently.
+  Monitor* global_lock   = allFun ? CodeCache_lock : NULL;
+  Monitor* function_lock = allFun ? NULL : CodeCache_lock;
+  ts_global.update(); // record starting point
+  MutexLockerEx mu2(global_lock, Mutex::_no_safepoint_check_flag);
+  if (global_lock != NULL) {
+    out->print_cr("\n__ CodeCache (global) lock wait took %10.3f seconds _________\n", ts_global.seconds());
+    ts_global.update(); // record starting point
+  }
 
   if (aggregate) {
-    // It is sufficient to hold the CodeCache_lock only for the aggregate step.
-    // All other functions operate on aggregated data - except MethodNames, but that should be safe.
-    // The separate CodeHeapStateAnalytics_lock protects the printing functions against
-    // concurrent aggregate steps. Acquire this lock before acquiring the CodeCache_lock.
-    // CodeHeapStateAnalytics_lock could be held by a concurrent thread for a long time,
-    // leading to an unnecessarily long hold time of the CodeCache_lock.
     ts.update(); // record starting point
-    MutexLockerEx mu2(CodeCache_lock, Mutex::_no_safepoint_check_flag);
-    out->cr();
-    out->print_cr("__ CodeCache lock wait took %10.3f seconds _________", ts.seconds());
-    out->cr();
+    MutexLockerEx mu3(function_lock, Mutex::_no_safepoint_check_flag);
+    if (function_lock != NULL) {
+      out->print_cr("\n__ CodeCache (function) lock wait took %10.3f seconds _________\n", ts.seconds());
+    }
 
     ts.update(); // record starting point
     CodeCache::aggregate(out, granularity);
-    out->cr();
-    out->print_cr("__ CodeCache lock hold took %10.3f seconds _________", ts.seconds());
-    out->cr();
+    if (function_lock != NULL) {
+      out->print_cr("\n__ CodeCache (function) lock hold took %10.3f seconds _________\n", ts.seconds());
+    }
   }
 
   if (usedSpace) CodeCache::print_usedSpace(out);
@@ -2737,10 +2746,16 @@
   if (methodCount) CodeCache::print_count(out);
   if (methodSpace) CodeCache::print_space(out);
   if (methodAge) CodeCache::print_age(out);
-  if (methodNames) CodeCache::print_names(out);
+  if (methodNames) {
+    // print_names() has shown to be sensitive to concurrent CodeHeap modifications.
+    // Therefore, request  the CodeCache_lock before calling...
+    MutexLockerEx mu3(function_lock, Mutex::_no_safepoint_check_flag);
+    CodeCache::print_names(out);
+  }
   if (discard) CodeCache::discard(out);
 
-  out->cr();
-  out->print_cr("__ CodeHeapStateAnalytics total duration %10.3f seconds _________", ts_total.seconds());
-  out->cr();
+  if (global_lock != NULL) {
+    out->print_cr("\n__ CodeCache (global) lock hold took %10.3f seconds _________\n", ts_global.seconds());
+  }
+  out->print_cr("\n__ CodeHeapStateAnalytics total duration %10.3f seconds _________\n", ts_total.seconds());
 }
--- a/src/hotspot/share/gc/g1/g1YoungRemSetSamplingThread.cpp	Wed Jan 16 19:09:16 2019 +0000
+++ b/src/hotspot/share/gc/g1/g1YoungRemSetSamplingThread.cpp	Wed Jan 16 20:53:09 2019 +0100
@@ -62,9 +62,8 @@
   }
 
   // Check if enough time has passed since the last GC.
-  uintx time_since_last_gc;
-  if ((G1PeriodicGCInterval == 0) ||
-      ((time_since_last_gc = (uintx)Universe::heap()->millis_since_last_gc()) < G1PeriodicGCInterval)) {
+  uintx time_since_last_gc = (uintx)Universe::heap()->millis_since_last_gc();
+  if ((time_since_last_gc < G1PeriodicGCInterval)) {
     log_debug(gc, periodic)("Last GC occurred " UINTX_FORMAT "ms before which is below threshold " UINTX_FORMAT "ms. Skipping.",
                             time_since_last_gc, G1PeriodicGCInterval);
     return false;
@@ -83,6 +82,10 @@
 }
 
 void G1YoungRemSetSamplingThread::check_for_periodic_gc(){
+  // If disabled, just return.
+  if (G1PeriodicGCInterval == 0) {
+    return;
+  }
   if ((os::elapsedTime() - _last_periodic_gc_attempt_s) > (G1PeriodicGCInterval / 1000.0)) {
     log_debug(gc, periodic)("Checking for periodic GC.");
     if (should_start_periodic_gc()) {
@@ -95,6 +98,13 @@
 void G1YoungRemSetSamplingThread::run_service() {
   double vtime_start = os::elapsedVTime();
 
+  // Print a message about periodic GC configuration.
+  if (G1PeriodicGCInterval != 0) {
+    log_info(gc)("Periodic GC enabled with interval " UINTX_FORMAT "ms", G1PeriodicGCInterval);
+  } else {
+    log_info(gc)("Periodic GC disabled");
+  }
+
   while (!should_terminate()) {
     sample_young_list_rs_lengths();
 
--- a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp	Wed Jan 16 19:09:16 2019 +0000
+++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp	Wed Jan 16 20:53:09 2019 +0100
@@ -97,7 +97,7 @@
     return false;
   }
 
-  if (n->is_CallJava() || n->Opcode() == Op_CallLeafNoFP) {
+  if (n->is_Call()) {
     return true;
   }
 
@@ -2659,9 +2659,35 @@
     wb->pin_and_expand_helper(phase);
   }
 
+  for (uint i = 0; i < enqueue_barriers.size(); i++) {
+    Node* barrier = enqueue_barriers.at(i);
+    Node* ctrl = phase->get_ctrl(barrier);
+    IdealLoopTree* loop = phase->get_loop(ctrl);
+    if (loop->_head->is_OuterStripMinedLoop()) {
+      // Expanding a barrier here will break loop strip mining
+      // verification. Transform the loop so the loop nest doesn't
+      // appear as strip mined.
+      OuterStripMinedLoopNode* outer = loop->_head->as_OuterStripMinedLoop();
+      hide_strip_mined_loop(outer, outer->unique_ctrl_out()->as_CountedLoop(), phase);
+    }
+  }
+
+  for (int i = ShenandoahBarrierSetC2::bsc2()->state()->shenandoah_barriers_count(); i > 0; i--) {
+    int cnt = ShenandoahBarrierSetC2::bsc2()->state()->shenandoah_barriers_count();
+    ShenandoahWriteBarrierNode* wb = ShenandoahBarrierSetC2::bsc2()->state()->shenandoah_barrier(i-1);
+    Node* ctrl = phase->get_ctrl(wb);
+    IdealLoopTree* loop = phase->get_loop(ctrl);
+    if (loop->_head->is_OuterStripMinedLoop()) {
+      // Expanding a barrier here will break loop strip mining
+      // verification. Transform the loop so the loop nest doesn't
+      // appear as strip mined.
+      OuterStripMinedLoopNode* outer = loop->_head->as_OuterStripMinedLoop();
+      hide_strip_mined_loop(outer, outer->unique_ctrl_out()->as_CountedLoop(), phase);
+    }
+  }
+
   MemoryGraphFixer fixer(Compile::AliasIdxRaw, true, phase);
   Unique_Node_List uses_to_ignore;
-  Unique_Node_List outer_lsms;
   for (uint i = 0; i < enqueue_barriers.size(); i++) {
     Node* barrier = enqueue_barriers.at(i);
     Node* pre_val = barrier->in(1);
@@ -2685,9 +2711,6 @@
 
     Node* init_ctrl = ctrl;
     IdealLoopTree* loop = phase->get_loop(ctrl);
-    if (loop->_head->is_OuterStripMinedLoop()) {
-      outer_lsms.push(loop->_head);
-    }
     Node* raw_mem = fixer.find_mem(ctrl, barrier);
     Node* init_raw_mem = raw_mem;
     Node* raw_mem_for_ctrl = fixer.find_mem(ctrl, NULL);
@@ -2832,9 +2855,6 @@
     Node* val = wb->in(ValueIn);
     Node* wbproj = wb->find_out_with(Op_ShenandoahWBMemProj);
     IdealLoopTree *loop = phase->get_loop(ctrl);
-    if (loop->_head->is_OuterStripMinedLoop()) {
-      outer_lsms.push(loop->_head);
-    }
 
     assert(val->Opcode() != Op_ShenandoahWriteBarrier, "No chain of write barriers");
 
@@ -3019,14 +3039,6 @@
   }
 
   assert(ShenandoahBarrierSetC2::bsc2()->state()->shenandoah_barriers_count() == 0, "all write barrier nodes should have been replaced");
-
-  for (uint i = 0; i < outer_lsms.size(); i++) {
-    // Expanding a barrier here will break loop strip mining
-    // verification. Transform the loop so the loop nest doesn't
-    // appear as strip mined.
-    OuterStripMinedLoopNode* outer = outer_lsms.at(i)->as_OuterStripMinedLoop();
-    hide_strip_mined_loop(outer, outer->unique_ctrl_out()->as_CountedLoop(), phase);
-  }
 }
 
 void ShenandoahWriteBarrierNode::move_heap_stable_test_out_of_loop(IfNode* iff, PhaseIdealLoop* phase) {
@@ -4274,5 +4286,3 @@
     _memory_nodes.map(c->_idx, mem->in(ShenandoahWBMemProjNode::WriteBarrier)->in(ShenandoahBarrierNode::Memory));
   }
 }
-
-
--- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp	Wed Jan 16 19:09:16 2019 +0000
+++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp	Wed Jan 16 20:53:09 2019 +0100
@@ -602,6 +602,17 @@
       return NULL;
   }
 
+  if (method->name() == vmSymbols::clone_name() &&
+      resolved == SystemDictionary::Object_klass() &&
+      recv_klass->is_array_klass()) {
+    // Resolution of the clone method on arrays always returns Object.clone even though that method
+    // has protected access.  There's some trickery in the access checking to make this all work out
+    // so it's necessary to pass in the array class as the resolved class to properly trigger this.
+    // Otherwise it's impossible to resolve the array clone methods through JVMCI.  See
+    // LinkResolver::check_method_accessability for the matching logic.
+    resolved = recv_klass;
+  }
+
   LinkInfo link_info(resolved, h_name, h_signature, caller_klass);
   methodHandle m;
   // Only do exact lookup if receiver klass has been linked.  Otherwise,
--- a/src/hotspot/share/opto/loopPredicate.cpp	Wed Jan 16 19:09:16 2019 +0000
+++ b/src/hotspot/share/opto/loopPredicate.cpp	Wed Jan 16 20:53:09 2019 +0100
@@ -160,7 +160,7 @@
   // When called from beautify_loops() idom is not constructed yet.
   if (_idom != NULL) {
     Node* ridom = idom(rgn);
-    Node* nrdom = dom_lca(ridom, new_iff);
+    Node* nrdom = dom_lca_internal(ridom, new_iff);
     set_idom(rgn, nrdom, dom_depth(rgn));
   }
 
--- a/src/java.base/share/classes/java/security/spec/PSSParameterSpec.java	Wed Jan 16 19:09:16 2019 +0000
+++ b/src/java.base/share/classes/java/security/spec/PSSParameterSpec.java	Wed Jan 16 20:53:09 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 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
@@ -26,7 +26,6 @@
 package java.security.spec;
 
 import java.util.Objects;
-import java.security.spec.MGF1ParameterSpec;
 
 /**
  * This class specifies a parameter spec for RSASSA-PSS signature scheme,
@@ -218,4 +217,14 @@
     public int getTrailerField() {
         return trailerField;
     }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("MD: " + mdName + "\n")
+                .append("MGF: " + mgfSpec + "\n")
+                .append("SaltLength: " + saltLen + "\n")
+                .append("TrailerField: " + trailerField + "\n");
+        return sb.toString();
+    }
 }
--- a/src/java.base/share/classes/sun/security/pkcs10/PKCS10.java	Wed Jan 16 19:09:16 2019 +0000
+++ b/src/java.base/share/classes/sun/security/pkcs10/PKCS10.java	Wed Jan 16 20:53:09 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 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
@@ -32,7 +32,6 @@
 
 import java.security.cert.CertificateException;
 import java.security.*;
-import java.security.spec.AlgorithmParameterSpec;
 
 import java.util.Base64;
 
@@ -237,10 +236,14 @@
          */
         AlgorithmId algId = null;
         try {
-            algId = AlgorithmId.get(signature.getAlgorithm());
+            AlgorithmParameters params = signature.getParameters();
+            algId = params == null
+                    ? AlgorithmId.get(signature.getAlgorithm())
+                    : AlgorithmId.get(params);
         } catch (NoSuchAlgorithmException nsae) {
             throw new SignatureException(nsae);
         }
+
         algId.encode(scratch);     // sig algorithm
         scratch.putBitString(sig);                      // sig
 
--- a/src/java.base/share/classes/sun/security/rsa/PSSParameters.java	Wed Jan 16 19:09:16 2019 +0000
+++ b/src/java.base/share/classes/sun/security/rsa/PSSParameters.java	Wed Jan 16 20:53:09 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 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
@@ -52,13 +52,7 @@
 
 public final class PSSParameters extends AlgorithmParametersSpi {
 
-    private String mdName;
-    private MGF1ParameterSpec mgfSpec;
-    private int saltLength;
-    private int trailerField;
-
-    private static final ObjectIdentifier OID_MGF1 =
-           ObjectIdentifier.newInternal(new int[] {1,2,840,113549,1,1,8});
+    private PSSParameterSpec spec;
 
     public PSSParameters() {
     }
@@ -71,9 +65,9 @@
                 ("Inappropriate parameter specification");
         }
         PSSParameterSpec spec = (PSSParameterSpec) paramSpec;
-        this.mdName = spec.getDigestAlgorithm();
+
         String mgfName = spec.getMGFAlgorithm();
-        if (!mgfName.equalsIgnoreCase("MGF1")) {
+        if (!spec.getMGFAlgorithm().equalsIgnoreCase("MGF1")) {
             throw new InvalidParameterSpecException("Unsupported mgf " +
                 mgfName + "; MGF1 only");
         }
@@ -82,31 +76,30 @@
             throw new InvalidParameterSpecException("Inappropriate mgf " +
                 "parameters; non-null MGF1ParameterSpec only");
         }
-        this.mgfSpec = (MGF1ParameterSpec) mgfSpec;
-        this.saltLength = spec.getSaltLength();
-        this.trailerField = spec.getTrailerField();
+        this.spec = spec;
     }
 
     @Override
     protected void engineInit(byte[] encoded) throws IOException {
         // first initialize with the DEFAULT values before
         // retrieving from the encoding bytes
-        this.mdName = DEFAULT.getDigestAlgorithm();
-        this.mgfSpec = (MGF1ParameterSpec) DEFAULT.getMGFParameters();
-        this.saltLength = DEFAULT.getSaltLength();
-        this.trailerField = DEFAULT.getTrailerField();
+        String mdName = DEFAULT.getDigestAlgorithm();
+        MGF1ParameterSpec mgfSpec = (MGF1ParameterSpec) DEFAULT.getMGFParameters();
+        int saltLength = DEFAULT.getSaltLength();
+        int trailerField = DEFAULT.getTrailerField();
 
         DerInputStream der = new DerInputStream(encoded);
         DerValue[] datum = der.getSequence(4);
+
         for (DerValue d : datum) {
             if (d.isContextSpecific((byte) 0x00)) {
                 // hash algid
-                this.mdName = AlgorithmId.parse
+                mdName = AlgorithmId.parse
                     (d.data.getDerValue()).getName();
             } else if (d.isContextSpecific((byte) 0x01)) {
                 // mgf algid
                 AlgorithmId val = AlgorithmId.parse(d.data.getDerValue());
-                if (!val.getOID().equals(OID_MGF1)) {
+                if (!val.getOID().equals(AlgorithmId.mgf1_oid)) {
                     throw new IOException("Only MGF1 mgf is supported");
                 }
                 AlgorithmId params = AlgorithmId.parse(
@@ -114,25 +107,25 @@
                 String mgfDigestName = params.getName();
                 switch (mgfDigestName) {
                 case "SHA-1":
-                    this.mgfSpec = MGF1ParameterSpec.SHA1;
+                    mgfSpec = MGF1ParameterSpec.SHA1;
                     break;
                 case "SHA-224":
-                    this.mgfSpec = MGF1ParameterSpec.SHA224;
+                    mgfSpec = MGF1ParameterSpec.SHA224;
                     break;
                 case "SHA-256":
-                    this.mgfSpec = MGF1ParameterSpec.SHA256;
+                    mgfSpec = MGF1ParameterSpec.SHA256;
                     break;
                 case "SHA-384":
-                    this.mgfSpec = MGF1ParameterSpec.SHA384;
+                    mgfSpec = MGF1ParameterSpec.SHA384;
                     break;
                 case "SHA-512":
-                    this.mgfSpec = MGF1ParameterSpec.SHA512;
+                    mgfSpec = MGF1ParameterSpec.SHA512;
                     break;
                 case "SHA-512/224":
-                    this.mgfSpec = MGF1ParameterSpec.SHA512_224;
+                    mgfSpec = MGF1ParameterSpec.SHA512_224;
                     break;
                 case "SHA-512/256":
-                    this.mgfSpec = MGF1ParameterSpec.SHA512_256;
+                    mgfSpec = MGF1ParameterSpec.SHA512_256;
                     break;
                 default:
                     throw new IOException
@@ -141,21 +134,24 @@
                 }
             } else if (d.isContextSpecific((byte) 0x02)) {
                 // salt length
-                this.saltLength = d.data.getDerValue().getInteger();
-                if (this.saltLength < 0) {
+                saltLength = d.data.getDerValue().getInteger();
+                if (saltLength < 0) {
                     throw new IOException("Negative value for saltLength");
                 }
             } else if (d.isContextSpecific((byte) 0x03)) {
                 // trailer field
-                this.trailerField = d.data.getDerValue().getInteger();
-                if (this.trailerField != 1) {
+                trailerField = d.data.getDerValue().getInteger();
+                if (trailerField != 1) {
                     throw new IOException("Unsupported trailerField value " +
-                    this.trailerField);
+                    trailerField);
                 }
             } else {
                 throw new IOException("Invalid encoded PSSParameters");
             }
         }
+
+        this.spec = new PSSParameterSpec(mdName, "MGF1", mgfSpec,
+                saltLength, trailerField);
     }
 
     @Override
@@ -173,9 +169,7 @@
             T engineGetParameterSpec(Class<T> paramSpec)
             throws InvalidParameterSpecException {
         if (PSSParameterSpec.class.isAssignableFrom(paramSpec)) {
-            return paramSpec.cast(
-                new PSSParameterSpec(mdName, "MGF1", mgfSpec,
-                                     saltLength, trailerField));
+            return paramSpec.cast(spec);
         } else {
             throw new InvalidParameterSpecException
                 ("Inappropriate parameter specification");
@@ -184,54 +178,7 @@
 
     @Override
     protected byte[] engineGetEncoded() throws IOException {
-        DerOutputStream tmp = new DerOutputStream();
-        DerOutputStream tmp2, tmp3;
-
-        // MD
-        AlgorithmId mdAlgId;
-        try {
-            mdAlgId = AlgorithmId.get(mdName);
-        } catch (NoSuchAlgorithmException nsae) {
-            throw new IOException("AlgorithmId " + mdName +
-                                  " impl not found");
-        }
-        tmp2 = new DerOutputStream();
-        mdAlgId.derEncode(tmp2);
-        tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0),
-                      tmp2);
-
-        // MGF
-        tmp2 = new DerOutputStream();
-        tmp2.putOID(OID_MGF1);
-        AlgorithmId mgfDigestId;
-        try {
-            mgfDigestId = AlgorithmId.get(mgfSpec.getDigestAlgorithm());
-        } catch (NoSuchAlgorithmException nase) {
-            throw new IOException("AlgorithmId " +
-                    mgfSpec.getDigestAlgorithm() + " impl not found");
-        }
-        mgfDigestId.encode(tmp2);
-        tmp3 = new DerOutputStream();
-        tmp3.write(DerValue.tag_Sequence, tmp2);
-        tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)1),
-                  tmp3);
-
-        // SaltLength
-        tmp2 = new DerOutputStream();
-        tmp2.putInteger(saltLength);
-        tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)2),
-                  tmp2);
-
-        // TrailerField
-        tmp2 = new DerOutputStream();
-        tmp2.putInteger(trailerField);
-        tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)3),
-                  tmp2);
-
-        // Put all together under a SEQUENCE tag
-        DerOutputStream out = new DerOutputStream();
-        out.write(DerValue.tag_Sequence, tmp);
-        return out.toByteArray();
+        return getEncoded(spec);
     }
 
     @Override
@@ -245,11 +192,83 @@
 
     @Override
     protected String engineToString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append("MD: " + mdName + "\n")
-            .append("MGF: MGF1" + mgfSpec.getDigestAlgorithm() + "\n")
-            .append("SaltLength: " + saltLength + "\n")
-            .append("TrailerField: " + trailerField + "\n");
-        return sb.toString();
+        return spec.toString();
+    }
+
+    /**
+     * Returns the encoding of a {@link PSSParameterSpec} object. This method
+     * is used in this class and {@link AlgorithmId}.
+     *
+     * @param spec a {@code PSSParameterSpec} object
+     * @return its DER encoding
+     * @throws IOException if the name of a MessageDigest or MaskGenAlgorithm
+     *          is unsupported
+     */
+    public static byte[] getEncoded(PSSParameterSpec spec) throws IOException {
+
+        AlgorithmParameterSpec mgfSpec = spec.getMGFParameters();
+        if (!(mgfSpec instanceof MGF1ParameterSpec)) {
+            throw new IOException("Cannot encode " + mgfSpec);
+        }
+
+        MGF1ParameterSpec mgf1Spec = (MGF1ParameterSpec)mgfSpec;
+
+        DerOutputStream tmp = new DerOutputStream();
+        DerOutputStream tmp2, tmp3;
+
+        // MD
+        AlgorithmId mdAlgId;
+        try {
+            mdAlgId = AlgorithmId.get(spec.getDigestAlgorithm());
+        } catch (NoSuchAlgorithmException nsae) {
+            throw new IOException("AlgorithmId " + spec.getDigestAlgorithm() +
+                    " impl not found");
+        }
+        if (!mdAlgId.getOID().equals(AlgorithmId.SHA_oid)) {
+            tmp2 = new DerOutputStream();
+            mdAlgId.derEncode(tmp2);
+            tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0),
+                    tmp2);
+        }
+
+        // MGF
+        AlgorithmId mgfDigestId;
+        try {
+            mgfDigestId = AlgorithmId.get(mgf1Spec.getDigestAlgorithm());
+        } catch (NoSuchAlgorithmException nase) {
+            throw new IOException("AlgorithmId " +
+                    mgf1Spec.getDigestAlgorithm() + " impl not found");
+        }
+
+        if (!mgfDigestId.getOID().equals(AlgorithmId.SHA_oid)) {
+            tmp2 = new DerOutputStream();
+            tmp2.putOID(AlgorithmId.mgf1_oid);
+            mgfDigestId.encode(tmp2);
+            tmp3 = new DerOutputStream();
+            tmp3.write(DerValue.tag_Sequence, tmp2);
+            tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 1),
+                    tmp3);
+        }
+
+        // SaltLength
+        if (spec.getSaltLength() != 20) {
+            tmp2 = new DerOutputStream();
+            tmp2.putInteger(spec.getSaltLength());
+            tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 2),
+                    tmp2);
+        }
+
+        // TrailerField
+        if (spec.getTrailerField() != PSSParameterSpec.TRAILER_FIELD_BC) {
+            tmp2 = new DerOutputStream();
+            tmp2.putInteger(spec.getTrailerField());
+            tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 3),
+                    tmp2);
+        }
+
+        // Put all together under a SEQUENCE tag
+        DerOutputStream out = new DerOutputStream();
+        out.write(DerValue.tag_Sequence, tmp);
+        return out.toByteArray();
     }
 }
--- a/src/java.base/share/classes/sun/security/ssl/DHKeyExchange.java	Wed Jan 16 19:09:16 2019 +0000
+++ b/src/java.base/share/classes/sun/security/ssl/DHKeyExchange.java	Wed Jan 16 20:53:09 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 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
@@ -220,8 +220,8 @@
         public byte[] encode() {
             // Note: the DH public value is encoded as a big-endian integer
             // and padded to the left with zeros to the size of p in bytes.
-            byte[] encoded = publicKey.getY().toByteArray();
-            int pSize = KeyUtil.getKeySize(publicKey);
+            byte[] encoded = Utilities.toByteArray(publicKey.getY());
+            int pSize = (KeyUtil.getKeySize(publicKey) + 7) >>> 3;
             if (pSize > 0 && encoded.length < pSize) {
                 byte[] buffer = new byte[pSize];
                 System.arraycopy(encoded, 0,
--- a/src/java.base/share/classes/sun/security/tools/keytool/CertAndKeyGen.java	Wed Jan 16 19:09:16 2019 +0000
+++ b/src/java.base/share/classes/sun/security/tools/keytool/CertAndKeyGen.java	Wed Jan 16 20:53:09 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 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
@@ -30,6 +30,7 @@
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateEncodingException;
 import java.security.*;
+import java.security.spec.AlgorithmParameterSpec;
 import java.security.spec.ECGenParameterSpec;
 import java.security.spec.NamedParameterSpec;
 import java.util.Date;
@@ -37,7 +38,6 @@
 import sun.security.pkcs10.PKCS10;
 import sun.security.x509.*;
 
-
 /**
  * Generate a pair of keys, and provide access to them.  This class is
  * provided primarily for ease of use.
@@ -282,12 +282,14 @@
                                    new CertificateValidity(firstDate,lastDate);
 
             X509CertInfo info = new X509CertInfo();
+            AlgorithmParameterSpec params = AlgorithmId
+                    .getDefaultAlgorithmParameterSpec(sigAlg, privateKey);
             // Add all mandatory attributes
             info.set(X509CertInfo.VERSION,
                      new CertificateVersion(CertificateVersion.V3));
             info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(
                     new java.util.Random().nextInt() & 0x7fffffff));
-            AlgorithmId algID = AlgorithmId.get(sigAlg);
+            AlgorithmId algID = AlgorithmId.getWithParameterSpec(sigAlg, params);
             info.set(X509CertInfo.ALGORITHM_ID,
                      new CertificateAlgorithmId(algID));
             info.set(X509CertInfo.SUBJECT, myname);
@@ -297,13 +299,19 @@
             if (ext != null) info.set(X509CertInfo.EXTENSIONS, ext);
 
             cert = new X509CertImpl(info);
-            cert.sign(privateKey, this.sigAlg);
+            cert.sign(privateKey,
+                    params,
+                    sigAlg,
+                    null);
 
             return (X509Certificate)cert;
 
         } catch (IOException e) {
              throw new CertificateEncodingException("getSelfCert: " +
                                                     e.getMessage());
+        } catch (InvalidAlgorithmParameterException e2) {
+            throw new SignatureException(
+                    "Unsupported PSSParameterSpec: " + e2.getMessage());
         }
     }
 
@@ -329,6 +337,7 @@
      * @exception InvalidKeyException on key handling errors.
      * @exception SignatureException on signature handling errors.
      */
+    // This method is not used inside JDK. Will not update it.
     public PKCS10 getCertRequest (X500Name myname)
     throws InvalidKeyException, SignatureException
     {
--- a/src/java.base/share/classes/sun/security/tools/keytool/Main.java	Wed Jan 16 19:09:16 2019 +0000
+++ b/src/java.base/share/classes/sun/security/tools/keytool/Main.java	Wed Jan 16 20:53:09 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -52,6 +52,7 @@
 
 
 import java.security.interfaces.ECKey;
+import java.security.spec.AlgorithmParameterSpec;
 import java.security.spec.ECParameterSpec;
 import java.text.Collator;
 import java.text.MessageFormat;
@@ -1431,14 +1432,16 @@
         signature.initSign(privateKey);
 
         X509CertInfo info = new X509CertInfo();
+        AlgorithmParameterSpec params = AlgorithmId
+                .getDefaultAlgorithmParameterSpec(sigAlgName, privateKey);
+        AlgorithmId algID = AlgorithmId.getWithParameterSpec(sigAlgName, params);
         info.set(X509CertInfo.VALIDITY, interval);
         info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(
                     new java.util.Random().nextInt() & 0x7fffffff));
         info.set(X509CertInfo.VERSION,
                     new CertificateVersion(CertificateVersion.V3));
         info.set(X509CertInfo.ALGORITHM_ID,
-                    new CertificateAlgorithmId(
-                        AlgorithmId.get(sigAlgName)));
+                    new CertificateAlgorithmId(algID));
         info.set(X509CertInfo.ISSUER, issuer);
 
         BufferedReader reader = new BufferedReader(new InputStreamReader(in));
@@ -1482,7 +1485,7 @@
                 signerCert.getPublicKey());
         info.set(X509CertInfo.EXTENSIONS, ext);
         X509CertImpl cert = new X509CertImpl(info);
-        cert.sign(privateKey, sigAlgName);
+        cert.sign(privateKey, params, sigAlgName, null);
         dumpCert(cert, out);
         for (Certificate ca: keyStore.getCertificateChain(alias)) {
             if (ca instanceof X509Certificate) {
@@ -1585,6 +1588,12 @@
 
         Signature signature = Signature.getInstance(sigAlgName);
         signature.initSign(privKey);
+        AlgorithmParameterSpec params = AlgorithmId
+                .getDefaultAlgorithmParameterSpec(sigAlgName, privKey);
+        if (params != null) {
+            signature.setParameter(params);
+        }
+
         X500Name subject = dname == null?
                 new X500Name(((X509Certificate)cert).getSubjectDN().toString()):
                 new X500Name(dname);
@@ -2962,7 +2971,9 @@
         // other solution: We first sign the cert, then retrieve the
         // outer sigalg and use it to set the inner sigalg
         X509CertImpl newCert = new X509CertImpl(certInfo);
-        newCert.sign(privKey, sigAlgName);
+        AlgorithmParameterSpec params = AlgorithmId
+                .getDefaultAlgorithmParameterSpec(sigAlgName, privKey);
+        newCert.sign(privKey, params, sigAlgName, null);
         AlgorithmId sigAlgid = (AlgorithmId)newCert.get(X509CertImpl.SIG_ALG);
         certInfo.set(CertificateAlgorithmId.NAME + "." +
                      CertificateAlgorithmId.ALGORITHM, sigAlgid);
@@ -2979,7 +2990,7 @@
         certInfo.set(X509CertInfo.EXTENSIONS, ext);
         // Sign the new certificate
         newCert = new X509CertImpl(certInfo);
-        newCert.sign(privKey, sigAlgName);
+        newCert.sign(privKey, params, sigAlgName, null);
 
         // Store the new certificate as a single-element certificate chain
         keyStore.setKeyEntry(alias, privKey,
--- a/src/java.base/share/classes/sun/security/x509/AlgorithmId.java	Wed Jan 16 19:09:16 2019 +0000
+++ b/src/java.base/share/classes/sun/security/x509/AlgorithmId.java	Wed Jan 16 20:53:09 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 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
@@ -26,9 +26,14 @@
 package sun.security.x509;
 
 import java.io.*;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.spec.MGF1ParameterSpec;
+import java.security.spec.PSSParameterSpec;
 import java.util.*;
 import java.security.*;
 
+import sun.security.rsa.PSSParameters;
 import sun.security.util.*;
 
 
@@ -190,7 +195,12 @@
             } else {
                 bytes.putNull();
             }*/
-            bytes.putNull();
+            if (algid.equals(RSASSA_PSS_oid)) {
+                // RFC 4055 3.3: when an RSASSA-PSS key does not require
+                // parameter validation, field is absent.
+            } else {
+                bytes.putNull();
+            }
         } else {
             bytes.putDerValue(params);
         }
@@ -689,6 +699,8 @@
                                             oid(1, 2, 840, 113549, 1, 1, 1);
     public static final ObjectIdentifier RSAES_OAEP_oid =
                                             oid(1, 2, 840, 113549, 1, 1, 7);
+    public static final ObjectIdentifier mgf1_oid =
+                                            oid(1, 2, 840, 113549, 1, 1, 8);
     public static final ObjectIdentifier RSASSA_PSS_oid =
                                             oid(1, 2, 840, 113549, 1, 1, 10);
 
@@ -1063,6 +1075,81 @@
         }
     }
 
+    // Most commonly used PSSParameterSpec and AlgorithmId
+    private static class PSSParamsHolder {
+
+        final static PSSParameterSpec PSS_256_SPEC = new PSSParameterSpec(
+                "SHA-256", "MGF1",
+                new MGF1ParameterSpec("SHA-256"),
+                32, PSSParameterSpec.TRAILER_FIELD_BC);
+        final static PSSParameterSpec PSS_384_SPEC = new PSSParameterSpec(
+                "SHA-384", "MGF1",
+                new MGF1ParameterSpec("SHA-384"),
+                48, PSSParameterSpec.TRAILER_FIELD_BC);
+        final static PSSParameterSpec PSS_512_SPEC = new PSSParameterSpec(
+                "SHA-512", "MGF1",
+                new MGF1ParameterSpec("SHA-512"),
+                64, PSSParameterSpec.TRAILER_FIELD_BC);
+
+        final static AlgorithmId PSS_256_ID;
+        final static AlgorithmId PSS_384_ID;
+        final static AlgorithmId PSS_512_ID;
+
+        static {
+            try {
+                PSS_256_ID = new AlgorithmId(RSASSA_PSS_oid,
+                        new DerValue(PSSParameters.getEncoded(PSS_256_SPEC)));
+                PSS_384_ID = new AlgorithmId(RSASSA_PSS_oid,
+                        new DerValue(PSSParameters.getEncoded(PSS_384_SPEC)));
+                PSS_512_ID = new AlgorithmId(RSASSA_PSS_oid,
+                        new DerValue(PSSParameters.getEncoded(PSS_512_SPEC)));
+            } catch (IOException e) {
+                throw new AssertionError("Should not happen", e);
+            }
+        }
+    }
+
+    public static AlgorithmId getWithParameterSpec(String algName,
+            AlgorithmParameterSpec spec) throws NoSuchAlgorithmException {
+
+        if (spec == null) {
+            return AlgorithmId.get(algName);
+        } else if (spec == PSSParamsHolder.PSS_256_SPEC) {
+            return PSSParamsHolder.PSS_256_ID;
+        } else if (spec == PSSParamsHolder.PSS_384_SPEC) {
+            return PSSParamsHolder.PSS_384_ID;
+        } else if (spec == PSSParamsHolder.PSS_512_SPEC) {
+            return PSSParamsHolder.PSS_512_ID;
+        } else {
+            try {
+                AlgorithmParameters result =
+                        AlgorithmParameters.getInstance(algName);
+                result.init(spec);
+                return get(result);
+            } catch (InvalidParameterSpecException | NoSuchAlgorithmException e) {
+                throw new ProviderException(e);
+            }
+        }
+    }
+
+    public static PSSParameterSpec getDefaultAlgorithmParameterSpec(
+            String sigAlg, PrivateKey k) {
+        if (sigAlg.equalsIgnoreCase("RSASSA-PSS")) {
+            switch (ifcFfcStrength(KeyUtil.getKeySize(k))) {
+                case "SHA256":
+                    return PSSParamsHolder.PSS_256_SPEC;
+                case "SHA384":
+                    return PSSParamsHolder.PSS_384_SPEC;
+                case "SHA512":
+                    return PSSParamsHolder.PSS_512_SPEC;
+                default:
+                    throw new AssertionError("Should not happen");
+            }
+        } else {
+            return null;
+        }
+    }
+
     // Values from SP800-57 part 1 rev 4 tables 2 and 3
     private static String ecStrength (int bitLength) {
         if (bitLength >= 512) { // 256 bits of strength
--- a/src/java.base/share/classes/sun/security/x509/X509CertImpl.java	Wed Jan 16 19:09:16 2019 +0000
+++ b/src/java.base/share/classes/sun/security/x509/X509CertImpl.java	Wed Jan 16 20:53:09 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 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,7 +42,6 @@
 
 import javax.security.auth.x500.X500Principal;
 
-import java.util.Base64;
 import sun.security.util.*;
 import sun.security.provider.X509Factory;
 
@@ -599,14 +598,10 @@
 
             sigEngine.initSign(key);
 
-            // set parameters after Signature.initSign/initVerify call, so
-            // the deferred provider selection happens when the key is set
-            try {
+            if (signingParams != null) {
+                // set parameters after Signature.initSign/initVerify call, so
+                // the deferred provider selection happens when the key is set
                 sigEngine.setParameter(signingParams);
-            } catch (UnsupportedOperationException e) {
-                // for backward compatibility, only re-throw when
-                // parameters is not null
-                if (signingParams != null) throw e;
             }
 
             // in case the name is reset
--- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java	Wed Jan 16 19:09:16 2019 +0000
+++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java	Wed Jan 16 20:53:09 2019 +0100
@@ -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
@@ -298,8 +298,6 @@
     private Rectangle normalBounds = null; // not-null only for undecorated maximized windows
     private CPlatformResponder responder;
     private long lastBecomeMainTime; // this is necessary to preserve right siblings order
-    private boolean maximizedBothState = false;
-    private boolean frameResizibilityChanged = false;
 
     public CPlatformWindow() {
         super(0, true);
@@ -402,7 +400,7 @@
 
         // Either java.awt.Frame or java.awt.Dialog can be resizable, however java.awt.Window is never resizable
         {
-            final boolean resizable = isTargetResizable();
+            final boolean resizable = isFrame ? ((Frame)target).isResizable() : (isDialog ? ((Dialog)target).isResizable() : false);
             styleBits = SET(styleBits, RESIZABLE, resizable);
             if (!resizable) {
                 styleBits = SET(styleBits, ZOOMABLE, false);
@@ -614,8 +612,6 @@
             setBounds(maximizedBounds.x, maximizedBounds.y,
                     maximizedBounds.width, maximizedBounds.height);
         }
-        setFrameResizibilityChanged(true);
-        updateResizableAndMaximizeState(true);
     }
 
     private void unmaximize() {
@@ -712,9 +708,11 @@
         // Manage the extended state when showing
         if (visible) {
             /* Frame or Dialog should be set property WINDOW_FULLSCREENABLE to true if the
-            Frame resizable and Frame state is not MAXIMIZED_BOTH or Dialog is resizable.
+            Frame or Dialog is resizable.
             **/
-            if (isTargetResizable()) {
+            final boolean resizable = (target instanceof Frame) ? ((Frame)target).isResizable() :
+            ((target instanceof Dialog) ? ((Dialog)target).isResizable() : false);
+            if (resizable) {
                 setCanFullscreen(true);
             }
 
@@ -730,11 +728,6 @@
                         frameState = Frame.ICONIFIED;
                     }
 
-                    if (isFrameResizibilityChanged()) {
-                        updateResizableAndMaximizeState(false);
-                        setFrameResizibilityChanged(false);
-                    }
-
                     switch (frameState) {
                         case Frame.ICONIFIED:
                             execute(CWrapper.NSWindow::miniaturize);
@@ -854,10 +847,9 @@
 
     @Override
     public void setResizable(final boolean resizable) {
-        boolean windowResizable = resizable && !isMaximizedBoth();
-        setCanFullscreen(windowResizable);
-        setStyleBits(RESIZABLE, windowResizable);
-        setStyleBits(ZOOMABLE, windowResizable);
+        setCanFullscreen(resizable);
+        setStyleBits(RESIZABLE, resizable);
+        setStyleBits(ZOOMABLE, resizable);
     }
 
     @Override
@@ -966,11 +958,6 @@
             windowState = Frame.ICONIFIED;
         }
 
-        if (isFrameResizibilityChanged()) {
-            updateResizableAndMaximizeState(false);
-            setFrameResizibilityChanged(false);
-        }
-
         switch (windowState) {
             case Frame.ICONIFIED:
                 if (prevWindowState == Frame.MAXIMIZED_BOTH) {
@@ -1174,21 +1161,6 @@
     }
 
     /*
-     * Resizibility of frame with state MAXIMIZED_BOTH is set to true to zoom
-     * the frame on double click on title bar and set to false later. This is
-     * required as frame won't zoom if resizibility of frame is false.
-     */
-    private void deliverDoubleClickOnTitlebar() {
-        if ((peer != null) && (target instanceof Frame)) {
-            if (isMaximizedBoth()) {
-                updateResizableAndMaximizeState(false);
-                execute(CWrapper.NSWindow::zoom);
-                updateResizableAndMaximizeState(true);
-            }
-        }
-    }
-
-    /*
      * Our focus model is synthetic and only non-simple window
      * may become natively focusable window.
      */
@@ -1353,33 +1325,6 @@
         }
         return false;
     }
-
-    private boolean isTargetResizable() {
-        if (target instanceof Frame) {
-            return ((Frame)target).isResizable() && !isMaximizedBoth();
-        } else if (target instanceof Dialog) {
-            return ((Dialog)target).isResizable();
-        }
-        return false;
-    }
-
-    private void updateResizableAndMaximizeState(boolean maximizeState) {
-        maximizedBothState = maximizeState;
-        setResizable(!maximizeState);
-    }
-
-    private boolean isMaximizedBoth() {
-        return maximizedBothState;
-    }
-
-    private void setFrameResizibilityChanged(boolean resize) {
-        frameResizibilityChanged = resize;
-    }
-
-    private boolean isFrameResizibilityChanged() {
-        return frameResizibilityChanged;
-    }
-
     // ----------------------------------------------------------------------
     //                          NATIVE CALLBACKS
     // ----------------------------------------------------------------------
--- a/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m	Wed Jan 16 19:09:16 2019 +0000
+++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m	Wed Jan 16 20:53:09 2019 +0100
@@ -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
@@ -965,11 +965,6 @@
                     // Currently, no need to deliver the whole NSEvent.
                     static JNF_MEMBER_CACHE(jm_deliverNCMouseDown, jc_CPlatformWindow, "deliverNCMouseDown", "()V");
                     JNFCallVoidMethod(env, platformWindow, jm_deliverNCMouseDown);
-                    // Deliver double click on title bar
-                    if ([event clickCount] > 1) {
-                        static JNF_MEMBER_CACHE(jm_deliverDoubleClickOnTitlebar, jc_CPlatformWindow, "deliverDoubleClickOnTitlebar", "()V");
-                        JNFCallVoidMethod(env, platformWindow, jm_deliverDoubleClickOnTitlebar);
-                    }
                     (*env)->DeleteLocalRef(env, platformWindow);
                 }
             }
--- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ResolvedJavaTypeResolveMethodTest.java	Wed Jan 16 19:09:16 2019 +0000
+++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ResolvedJavaTypeResolveMethodTest.java	Wed Jan 16 20:53:09 2019 +0100
@@ -168,6 +168,26 @@
 
     }
 
+    static class ClassType {
+    }
+
+    interface InterfaceType {
+    }
+
+    @Test
+    public void testCloneAccessibility() {
+        /*
+         * The resolution machinery for clone on arrays has some hacks in that show up in odd places
+         * so make sure that resolveMethod works as expected.
+         */
+        ResolvedJavaType interfaceType = getType(InterfaceType.class);
+        ResolvedJavaType classType = getType(ClassType.class);
+        ResolvedJavaType arrayType = getType(double[].class);
+        ResolvedJavaMethod cloneMethod = getMethod(getType(Object.class), "clone");
+        assertEquals("Can't resolve clone for class", cloneMethod, arrayType.resolveMethod(cloneMethod, classType));
+        assertEquals("Can't resolve clone for interface", cloneMethod, arrayType.resolveMethod(cloneMethod, interfaceType));
+    }
+
     static ResolvedJavaMethod getMethod(ResolvedJavaType type, String methodName) {
         for (ResolvedJavaMethod method : type.getDeclaredMethods()) {
             if (method.getName().equals(methodName)) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/gc/g1/TestPeriodicLogMessages.java	Wed Jan 16 20:53:09 2019 +0100
@@ -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.
+ */
+
+/**
+ * @test TestPeriodicLogMessages
+ * @bug 8216490
+ * @requires vm.gc.G1
+ * @summary Verify that log messages are printed as expected
+ * @library /test/lib /
+ * @modules java.base/jdk.internal.misc
+ * @modules java.management/sun.management
+ */
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+import jdk.test.lib.Platform;
+
+public class TestPeriodicLogMessages {
+
+    public static void main(String[] args) throws Exception {
+        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC",
+                                                                  "-XX:G1PeriodicGCInterval=0",
+                                                                  "-Xlog:gc,gc+periodic=debug",
+                                                                  "-Xmx10M",
+                                                                  GCTest.class.getName());
+
+        OutputAnalyzer output = new OutputAnalyzer(pb.start());
+        output.shouldContain("Periodic GC disabled");
+        output.shouldNotContain("Checking for periodic GC");
+        output.shouldHaveExitValue(0);
+
+        pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC",
+                                                   "-XX:G1PeriodicGCInterval=100",
+                                                   "-Xlog:gc,gc+periodic=debug",
+                                                   "-Xmx10M",
+                                                   GCTest.class.getName());
+
+        output = new OutputAnalyzer(pb.start());
+        output.shouldContain("Periodic GC enabled with interval 100ms");
+        output.shouldContain("Checking for periodic GC");
+        output.shouldHaveExitValue(0);
+    }
+
+    static class GCTest {
+        public static void main(String [] args) throws Exception {
+            System.out.println("Waiting for messages...");
+            Thread.sleep(1000);
+            System.out.println("Done");
+        }
+    }
+}
+
+
--- a/test/jdk/java/awt/Frame/UnfocusableMaximizedFrameResizablity/UnfocusableMaximizedFrameResizablity.java	Wed Jan 16 19:09:16 2019 +0000
+++ b/test/jdk/java/awt/Frame/UnfocusableMaximizedFrameResizablity/UnfocusableMaximizedFrameResizablity.java	Wed Jan 16 20:53:09 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -24,7 +24,7 @@
 /*
   @test
   @key headful
-  @bug 4980161 7158623 8204860 8208125
+  @bug 4980161 7158623 8204860 8208125 8215280
   @summary Setting focusable window state to false makes the maximized frame resizable
   @compile UnfocusableMaximizedFrameResizablity.java
   @run main UnfocusableMaximizedFrameResizablity
@@ -47,8 +47,15 @@
 
     private static void createAndShowFrame() throws Exception {
 
+        //MAXIMIZED_BOTH frame is resizable on Mac OS by default. Nothing to test.
+        if (System.getProperty("os.name").toLowerCase().startsWith("mac")) {
+            cleanup();
+            return;
+        }
+
         //The MAXIMIZED_BOTH state is not supported by the toolkit. Nothing to test.
         if (!Toolkit.getDefaultToolkit().isFrameStateSupported(Frame.MAXIMIZED_BOTH)) {
+            cleanup();
             return;
         }
 
@@ -93,7 +100,9 @@
     }
 
     private static void cleanup() {
-        frame.dispose();
+        if (frame != null) {
+            frame.dispose();
+        }
         isProgInterruption = true;
         mainThread.interrupt();
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/sun/security/tools/keytool/PSS.java	Wed Jan 16 20:53:09 2019 +0100
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8215694
+ * @summary keytool cannot generate RSASSA-PSS certificates
+ * @library /test/lib
+ * @modules java.base/sun.security.util
+ *          java.base/sun.security.x509
+ * @run main PSS
+ */
+
+import jdk.test.lib.Asserts;
+import jdk.test.lib.SecurityTools;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.security.DerUtils;
+import sun.security.util.ObjectIdentifier;
+import sun.security.x509.AlgorithmId;
+
+import java.io.File;
+import java.security.KeyStore;
+import java.security.cert.X509Certificate;
+
+public class PSS {
+
+    public static void main(String[] args) throws Exception {
+
+        genkeypair("p", "-keyalg RSASSA-PSS -sigalg RSASSA-PSS")
+                .shouldHaveExitValue(0);
+
+        genkeypair("a", "-keyalg RSA -sigalg RSASSA-PSS -keysize 2048")
+                .shouldHaveExitValue(0);
+
+        genkeypair("b", "-keyalg RSA -sigalg RSASSA-PSS -keysize 4096")
+                .shouldHaveExitValue(0);
+
+        genkeypair("c", "-keyalg RSA -sigalg RSASSA-PSS -keysize 8192")
+                .shouldHaveExitValue(0);
+
+        KeyStore ks = KeyStore.getInstance(
+                new File("ks"), "changeit".toCharArray());
+
+        check((X509Certificate)ks.getCertificate("p"), "RSASSA-PSS",
+                AlgorithmId.SHA256_oid);
+
+        check((X509Certificate)ks.getCertificate("a"), "RSA",
+                AlgorithmId.SHA256_oid);
+
+        check((X509Certificate)ks.getCertificate("b"), "RSA",
+                AlgorithmId.SHA384_oid);
+
+        check((X509Certificate)ks.getCertificate("c"), "RSA",
+                AlgorithmId.SHA512_oid);
+
+        // More commands
+        kt("-certreq -alias p -sigalg RSASSA-PSS -file p.req")
+                .shouldHaveExitValue(0);
+
+        kt("-gencert -alias a -sigalg RSASSA-PSS -infile p.req -outfile p.cert")
+                .shouldHaveExitValue(0);
+
+        kt("-importcert -alias p -file p.cert")
+                .shouldHaveExitValue(0);
+
+        kt("-selfcert -alias p -sigalg RSASSA-PSS")
+                .shouldHaveExitValue(0);
+    }
+
+    static OutputAnalyzer genkeypair(String alias, String options)
+            throws Exception {
+        return kt("-genkeypair -alias " + alias
+                + " -dname CN=" + alias + " " + options);
+    }
+
+    static OutputAnalyzer kt(String cmd)
+            throws Exception {
+        return SecurityTools.keytool("-storepass changeit -keypass changeit "
+                + "-keystore ks " + cmd);
+    }
+
+    static void check(X509Certificate cert, String expectedKeyAlg,
+            ObjectIdentifier expectedMdAlg) throws Exception {
+        Asserts.assertEQ(cert.getPublicKey().getAlgorithm(), expectedKeyAlg);
+        Asserts.assertEQ(cert.getSigAlgName(), "RSASSA-PSS");
+        DerUtils.checkAlg(cert.getSigAlgParams(), "000", expectedMdAlg);
+    }
+}