changeset 55873:59642852dee0

Merge
author psadhukhan
date Thu, 13 Jun 2019 11:31:36 +0530
parents 5d5fccc4fd3f 03c98877f3bd
children 5c4f1b7c753b
files
diffstat 115 files changed, 6720 insertions(+), 1874 deletions(-) [+]
line wrap: on
line diff
--- a/make/lib/Lib-java.security.jgss.gmk	Wed Jun 12 10:02:49 2019 +0530
+++ b/make/lib/Lib-java.security.jgss.gmk	Thu Jun 13 11:31:36 2019 +0530
@@ -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
@@ -57,6 +57,17 @@
     ))
 
     TARGETS += $(BUILD_LIBW2K_LSA_AUTH)
+
+    $(eval $(call SetupJdkLibrary, BUILD_LIBSSPI_BRIDGE, \
+        NAME := sspi_bridge, \
+        OPTIMIZATION := LOW, \
+        CFLAGS := $(CFLAGS_JDKLIB) \
+            -I$(TOPDIR)/src/java.security.jgss/share/native/libj2gss, \
+        LDFLAGS := $(LDFLAGS_JDKLIB) \
+            $(call SET_SHARED_LIBRARY_ORIGIN) \
+    ))
+
+    TARGETS += $(BUILD_LIBSSPI_BRIDGE)
   endif
 
   ifeq ($(call isTargetOs, macosx), true)
--- a/src/hotspot/cpu/ppc/ppc.ad	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/hotspot/cpu/ppc/ppc.ad	Thu Jun 13 11:31:36 2019 +0530
@@ -1,6 +1,6 @@
 //
-// Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
-// Copyright (c) 2012, 2018 SAP SE. All rights reserved.
+// Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
+// Copyright (c) 2012, 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
@@ -4649,6 +4649,16 @@
   interface(CONST_INTER);
 %}
 
+// Double Immediate: +0.0d.
+operand immD_0() %{
+  predicate(jlong_cast(n->getd()) == 0);
+  match(ConD);
+
+  op_cost(0);
+  format %{ %}
+  interface(CONST_INTER);
+%}
+
 // Integer Register Operands
 // Integer Destination Register
 // See definition of reg_class bits32_reg_rw.
@@ -14027,7 +14037,7 @@
 instruct repl4S_immI0(iRegLdst dst, immI_0 zero) %{
   match(Set dst (ReplicateS zero));
   predicate(n->as_Vector()->length() == 4);
-  format %{ "LI      $dst, #0 \t// replicate4C" %}
+  format %{ "LI      $dst, #0 \t// replicate4S" %}
   size(4);
   ins_encode %{
     // TODO: PPC port $archOpcode(ppc64Opcode_addi);
@@ -14039,7 +14049,7 @@
 instruct repl4S_immIminus1(iRegLdst dst, immI_minus1 src) %{
   match(Set dst (ReplicateS src));
   predicate(n->as_Vector()->length() == 4);
-  format %{ "LI      $dst, -1 \t// replicate4C" %}
+  format %{ "LI      $dst, -1 \t// replicate4S" %}
   size(4);
   ins_encode %{
     // TODO: PPC port $archOpcode(ppc64Opcode_addi);
@@ -14080,7 +14090,7 @@
   match(Set dst (ReplicateS src));
   predicate(n->as_Vector()->length() == 8);
 
-  format %{ "XXLEQV      $dst, $src \t// replicate16B" %}
+  format %{ "XXLEQV      $dst, $src \t// replicate8S" %}
   size(4);
   ins_encode %{
     __ xxleqv($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister);
@@ -14101,7 +14111,7 @@
 instruct repl2I_immI0(iRegLdst dst, immI_0 zero) %{
   match(Set dst (ReplicateI zero));
   predicate(n->as_Vector()->length() == 2);
-  format %{ "LI      $dst, #0 \t// replicate4C" %}
+  format %{ "LI      $dst, #0 \t// replicate2I" %}
   size(4);
   ins_encode %{
     // TODO: PPC port $archOpcode(ppc64Opcode_addi);
@@ -14113,7 +14123,7 @@
 instruct repl2I_immIminus1(iRegLdst dst, immI_minus1 src) %{
   match(Set dst (ReplicateI src));
   predicate(n->as_Vector()->length() == 2);
-  format %{ "LI      $dst, -1 \t// replicate4C" %}
+  format %{ "LI      $dst, -1 \t// replicate2I" %}
   size(4);
   ins_encode %{
     // TODO: PPC port $archOpcode(ppc64Opcode_addi);
@@ -14687,7 +14697,7 @@
   ins_pipe(pipe_class_default);
 %}
 
-instruct repl2D_immI0(vecX dst, immI_0 zero) %{
+instruct repl2D_immD0(vecX dst, immD_0 zero) %{
   match(Set dst (ReplicateD zero));
   predicate(n->as_Vector()->length() == 2);
 
@@ -14699,18 +14709,6 @@
   ins_pipe(pipe_class_default);
 %}
 
-instruct repl2D_immIminus1(vecX dst, immI_minus1 src) %{
-  match(Set dst (ReplicateD src));
-  predicate(n->as_Vector()->length() == 2);
-
-  format %{ "XXLEQV      $dst, $src \t// replicate16B" %}
-  size(4);
-  ins_encode %{
-    __ xxleqv($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister);
-  %}
-  ins_pipe(pipe_class_default);
-%}
-
 instruct mtvsrd(vecX dst, iRegLsrc src) %{
   predicate(false);
   effect(DEF dst, USE src);
@@ -14772,7 +14770,7 @@
   match(Set dst (ReplicateL src));
   predicate(n->as_Vector()->length() == 2);
 
-  format %{ "XXLEQV      $dst, $src \t// replicate16B" %}
+  format %{ "XXLEQV      $dst, $src \t// replicate2L" %}
   size(4);
   ins_encode %{
     __ xxleqv($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister);
--- a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp	Thu Jun 13 11:31:36 2019 +0530
@@ -82,7 +82,18 @@
 }
 
 void LIR_Assembler::clinit_barrier(ciMethod* method) {
-  ShouldNotReachHere(); // not implemented
+  assert(!method->holder()->is_not_initialized(), "initialization should have been started");
+
+  Label L_skip_barrier;
+  Register klass = Z_R1_scratch;
+
+  metadata2reg(method->holder()->constant_encoding(), klass);
+  __ clinit_barrier(klass, Z_thread, &L_skip_barrier /*L_fast_path*/);
+
+  __ load_const_optimized(klass, SharedRuntime::get_handle_wrong_method_stub());
+  __ z_br(klass);
+
+  __ bind(L_skip_barrier);
 }
 
 void LIR_Assembler::osr_entry() {
--- a/src/hotspot/cpu/s390/interp_masm_s390.cpp	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/hotspot/cpu/s390/interp_masm_s390.cpp	Thu Jun 13 11:31:36 2019 +0530
@@ -1,6 +1,6 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2016, 2018 SAP SE. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -414,6 +414,19 @@
   BLOCK_COMMENT("}");
 }
 
+void InterpreterMacroAssembler::load_resolved_method_at_index(int byte_no,
+                                                              Register cache,
+                                                              Register cpe_offset,
+                                                              Register method) {
+  const int method_offset = in_bytes(
+    ConstantPoolCache::base_offset() +
+      ((byte_no == TemplateTable::f2_byte)
+       ? ConstantPoolCacheEntry::f2_offset()
+       : ConstantPoolCacheEntry::f1_offset()));
+
+  z_lg(method, Address(cache, cpe_offset, method_offset)); // get f1 Method*
+}
+
 // Generate a subtype check: branch to ok_is_subtype if sub_klass is
 // a subtype of super_klass. Blows registers Rsuper_klass, Rsub_klass, tmp1, tmp2.
 void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass,
@@ -2175,7 +2188,7 @@
   Register R_f1_sender_sp = tmp1;
   Register R_f2_sp = tmp2;
 
-  // Tirst check the for the interpreter frame's magic.
+  // First check for the interpreter frame's magic.
   asm_assert_ijava_state_magic(R_f2_sp/*tmp*/);
   z_lg(R_f2_sp, _z_parent_ijava_frame_abi(callers_sp), Z_fp);
   z_lg(R_f1_sender_sp, _z_ijava_state_neg(sender_sp), Z_fp);
--- a/src/hotspot/cpu/s390/interp_masm_s390.hpp	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/hotspot/cpu/s390/interp_masm_s390.hpp	Thu Jun 13 11:31:36 2019 +0530
@@ -120,6 +120,8 @@
   // load cpool->resolved_klass_at(index)
   void load_resolved_klass_at_offset(Register cpool, Register offset, Register iklass);
 
+  void load_resolved_method_at_index(int byte_no, Register cache, Register cpe_offset, Register method);
+
   // Pop topmost element from stack. It just disappears. Useful if
   // consumed previously by access via stackTop().
   void popx(int len);
--- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp	Thu Jun 13 11:31:36 2019 +0530
@@ -1,6 +1,6 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2016, 2018, SAP SE. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -3130,6 +3130,33 @@
   BLOCK_COMMENT("} check_klass_subtype");
 }
 
+void MacroAssembler::clinit_barrier(Register klass, Register thread, Label* L_fast_path, Label* L_slow_path) {
+  assert(L_fast_path != NULL || L_slow_path != NULL, "at least one is required");
+
+  Label L_fallthrough;
+  if (L_fast_path == NULL) {
+    L_fast_path = &L_fallthrough;
+  } else if (L_slow_path == NULL) {
+    L_slow_path = &L_fallthrough;
+  }
+
+  // Fast path check: class is fully initialized
+  z_cli(Address(klass, InstanceKlass::init_state_offset()), InstanceKlass::fully_initialized);
+  z_bre(*L_fast_path);
+
+  // Fast path check: current thread is initializer thread
+  z_cg(thread, Address(klass, InstanceKlass::init_thread_offset()));
+  if (L_slow_path == &L_fallthrough) {
+    z_bre(*L_fast_path);
+  } else if (L_fast_path == &L_fallthrough) {
+    z_brne(*L_slow_path);
+  } else {
+    Unimplemented();
+  }
+
+  bind(L_fallthrough);
+}
+
 // Increment a counter at counter_address when the eq condition code is
 // set. Kills registers tmp1_reg and tmp2_reg and preserves the condition code.
 void MacroAssembler::increment_counter_eq(address counter_address, Register tmp1_reg, Register tmp2_reg) {
@@ -4339,14 +4366,19 @@
   z_lg(result, 0, result);
 }
 
-void MacroAssembler::load_mirror(Register mirror, Register method) {
-  mem2reg_opt(mirror, Address(method, Method::const_offset()));
-  mem2reg_opt(mirror, Address(mirror, ConstMethod::constants_offset()));
+void MacroAssembler::load_mirror_from_const_method(Register mirror, Register const_method) {
+  mem2reg_opt(mirror, Address(const_method, ConstMethod::constants_offset()));
   mem2reg_opt(mirror, Address(mirror, ConstantPool::pool_holder_offset_in_bytes()));
   mem2reg_opt(mirror, Address(mirror, Klass::java_mirror_offset()));
   resolve_oop_handle(mirror);
 }
 
+void MacroAssembler::load_method_holder(Register holder, Register method) {
+  mem2reg_opt(holder, Address(method, Method::const_offset()));
+  mem2reg_opt(holder, Address(holder, ConstMethod::constants_offset()));
+  mem2reg_opt(holder, Address(holder, ConstantPool::pool_holder_offset_in_bytes()));
+}
+
 //---------------------------------------------------------------
 //---  Operations on arrays.
 //---------------------------------------------------------------
--- a/src/hotspot/cpu/s390/macroAssembler_s390.hpp	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/hotspot/cpu/s390/macroAssembler_s390.hpp	Thu Jun 13 11:31:36 2019 +0530
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2016, 2018, SAP SE. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -713,6 +713,11 @@
                            Register temp2_reg,
                            Label&   L_success);
 
+  void clinit_barrier(Register klass,
+                      Register thread,
+                      Label* L_fast_path = NULL,
+                      Label* L_slow_path = NULL);
+
   // Increment a counter at counter_address when the eq condition code is set.
   // Kills registers tmp1_reg and tmp2_reg and preserves the condition code.
   void increment_counter_eq(address counter_address, Register tmp1_reg, Register tmp2_reg);
@@ -823,7 +828,8 @@
                    Register Rbase = Z_R1, int pow2_offset = -1);
 
   void resolve_oop_handle(Register result);
-  void load_mirror(Register mirror, Register method);
+  void load_mirror_from_const_method(Register mirror, Register const_method);
+  void load_method_holder(Register holder, Register method);
 
   //--------------------------
   //---  Operations on arrays.
--- a/src/hotspot/cpu/s390/s390.ad	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/hotspot/cpu/s390/s390.ad	Thu Jun 13 11:31:36 2019 +0530
@@ -867,6 +867,23 @@
 
   assert(framesize % wordSize == 0, "must preserve wordSize alignment");
 
+  if (C->clinit_barrier_on_entry()) {
+    assert(!C->method()->holder()->is_not_initialized(), "initialization should have been started");
+
+    Label L_skip_barrier;
+    Register klass = Z_R1_scratch;
+
+    // Notify OOP recorder (don't need the relocation)
+    AddressLiteral md = __ constant_metadata_address(C->method()->holder()->constant_encoding());
+    __ load_const_optimized(klass, md.value());
+    __ clinit_barrier(klass, Z_thread, &L_skip_barrier /*L_fast_path*/);
+
+    __ load_const_optimized(klass, SharedRuntime::get_handle_wrong_method_stub());
+    __ z_br(klass);
+
+    __ bind(L_skip_barrier);
+  }
+
   // Calls to C2R adapters often do not accept exceptional returns.
   // We require that their callers must bang for them. But be
   // careful, because some VM calls (such as call site linkage) can
--- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp	Thu Jun 13 11:31:36 2019 +0530
@@ -1832,6 +1832,20 @@
   //---------------------------------------------------------------------
   wrapper_VEPStart = __ offset();
 
+  if (VM_Version::supports_fast_class_init_checks() && method->needs_clinit_barrier()) {
+    Label L_skip_barrier;
+    Register klass = Z_R1_scratch;
+    // Notify OOP recorder (don't need the relocation)
+    AddressLiteral md = __ constant_metadata_address(method->method_holder());
+    __ load_const_optimized(klass, md.value());
+    __ clinit_barrier(klass, Z_thread, &L_skip_barrier /*L_fast_path*/);
+
+    __ load_const_optimized(klass, SharedRuntime::get_handle_wrong_method_stub());
+    __ z_br(klass);
+
+    __ bind(L_skip_barrier);
+  }
+
   __ save_return_pc();
   __ generate_stack_overflow_check(frame_size_in_bytes);  // Check before creating frame.
 #ifndef USE_RESIZE_FRAME
@@ -2696,8 +2710,28 @@
     // Fallthru to VEP. Duplicate LTG, but saved taken branch.
   }
 
-  address c2i_entry;
-  c2i_entry = gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
+  address c2i_entry = __ pc();
+
+  // Class initialization barrier for static methods
+  if (VM_Version::supports_fast_class_init_checks()) {
+    Label L_skip_barrier;
+
+    { // Bypass the barrier for non-static methods
+      __ testbit(Address(Z_method, Method::access_flags_offset()), JVM_ACC_STATIC_BIT);
+      __ z_bfalse(L_skip_barrier); // non-static
+    }
+
+    Register klass = Z_R11;
+    __ load_method_holder(klass, Z_method);
+    __ clinit_barrier(klass, Z_thread, &L_skip_barrier /*L_fast_path*/);
+
+    __ load_const_optimized(klass, SharedRuntime::get_handle_wrong_method_stub());
+    __ z_br(klass);
+
+    __ bind(L_skip_barrier);
+  }
+
+  gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
 
   return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
 }
--- a/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp	Thu Jun 13 11:31:36 2019 +0530
@@ -1,6 +1,6 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2016, 2018, SAP SE. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -821,7 +821,7 @@
   const int page_size = os::vm_page_size();
   NearLabel after_frame_check;
 
-  BLOCK_COMMENT("counter_overflow {");
+  BLOCK_COMMENT("stack_overflow_check {");
 
   assert_different_registers(frame_size, tmp1);
 
@@ -883,7 +883,7 @@
   // If you get to here, then there is enough stack space.
   __ bind(after_frame_check);
 
-  BLOCK_COMMENT("} counter_overflow");
+  BLOCK_COMMENT("} stack_overflow_check");
 }
 
 // Allocate monitor and lock method (asm interpreter).
@@ -927,7 +927,9 @@
     __ bind(static_method);
 
     // Lock the java mirror.
-    __ load_mirror(object, method);
+    // Load mirror from interpreter frame.
+    __ z_lg(object, _z_ijava_state_neg(mirror), Z_fp);
+
 #ifdef ASSERT
     {
       NearLabel L;
@@ -991,20 +993,20 @@
   // Allocate space for locals other than the parameters, the
   // interpreter state, monitors, and the expression stack.
 
-  const Register local_count     = Z_ARG5;
-  const Register fp              = Z_tmp_2;
+  const Register local_count  = Z_ARG5;
+  const Register fp           = Z_tmp_2;
+  const Register const_method = Z_ARG1;
 
   BLOCK_COMMENT("generate_fixed_frame {");
-
   {
   // local registers
   const Register top_frame_size  = Z_ARG2;
   const Register sp_after_resize = Z_ARG3;
   const Register max_stack       = Z_ARG4;
 
-  // local_count = method->constMethod->max_locals();
-  __ z_lg(Z_R1_scratch, Address(Z_method, Method::const_offset()));
-  __ z_llgh(local_count, Address(Z_R1_scratch, ConstMethod::size_of_locals_offset()));
+  __ z_lg(const_method, Address(Z_method, Method::const_offset()));
+  __ z_llgh(max_stack, Address(const_method, ConstMethod::size_of_parameters_offset()));
+  __ z_sllg(Z_locals /*parameter_count bytes*/, max_stack /*parameter_count*/, LogBytesPerWord);
 
   if (native_call) {
     // If we're calling a native method, we replace max_stack (which is
@@ -1024,9 +1026,6 @@
     // area, so we need to allocate at least that much even though we're
     // going to throw it away.
     //
-
-    __ z_lg(Z_R1_scratch, Address(Z_method, Method::const_offset()));
-    __ z_llgh(max_stack,  Address(Z_R1_scratch, ConstMethod::size_of_parameters_offset()));
     __ add2reg(max_stack, 2);
 
     NearLabel passing_args_on_stack;
@@ -1042,14 +1041,14 @@
     __ bind(passing_args_on_stack);
   } else {
     // !native_call
-    __ z_lg(max_stack, method_(const));
+    // local_count = method->constMethod->max_locals();
+    __ z_llgh(local_count, Address(const_method, ConstMethod::size_of_locals_offset()));
 
     // Calculate number of non-parameter locals (in slots):
-    __ z_lg(Z_R1_scratch, Address(Z_method, Method::const_offset()));
-    __ z_sh(local_count, Address(Z_R1_scratch, ConstMethod::size_of_parameters_offset()));
+    __ z_sgr(local_count, max_stack);
 
     // max_stack = method->max_stack();
-    __ z_llgh(max_stack, Address(max_stack, ConstMethod::max_stack_offset()));
+    __ z_llgh(max_stack, Address(const_method, ConstMethod::max_stack_offset()));
     // max_stack in bytes
     __ z_sllg(max_stack, max_stack, LogBytesPerWord);
   }
@@ -1089,14 +1088,15 @@
   // delta = PARENT_IJAVA_FRAME_ABI + (locals_count - params_count)
 
   __ add2reg(sp_after_resize, (Interpreter::stackElementSize) - (frame::z_parent_ijava_frame_abi_size), Z_esp);
-  __ z_sllg(Z_R0_scratch, local_count, LogBytesPerWord); // Params have already been subtracted from local_count.
-  __ z_slgr(sp_after_resize, Z_R0_scratch);
+  if (!native_call) {
+    __ z_sllg(Z_R0_scratch, local_count, LogBytesPerWord); // Params have already been subtracted from local_count.
+    __ z_slgr(sp_after_resize, Z_R0_scratch);
+  }
 
   // top_frame_size = TOP_IJAVA_FRAME_ABI + max_stack + size of interpreter state
   __ add2reg(top_frame_size,
              frame::z_top_ijava_frame_abi_size +
-             frame::z_ijava_state_size +
-             frame::interpreter_frame_monitor_size() * wordSize,
+             frame::z_ijava_state_size,
              max_stack);
 
   if (!native_call) {
@@ -1104,7 +1104,7 @@
     // Native calls don't need the stack size check since they have no
     // expression stack and the arguments are already on the stack and
     // we only add a handful of words to the stack.
-    Register frame_size = max_stack; // Reuse the regiser for max_stack.
+    Register frame_size = max_stack; // Reuse the register for max_stack.
     __ z_lgr(frame_size, Z_SP);
     __ z_sgr(frame_size, sp_after_resize);
     __ z_agr(frame_size, top_frame_size);
@@ -1136,13 +1136,12 @@
 #endif
 
   // Save sender SP from F1 (i.e. before it was potentially modified by an
-  // adapter) into F0's interpreter state. We us it as well to revert
+  // adapter) into F0's interpreter state. We use it as well to revert
   // resizing the frame above.
   __ z_stg(Z_R10, _z_ijava_state_neg(sender_sp), fp);
 
-  // Load cp cache and save it at the and of this block.
-  __ z_lg(Z_R1_scratch, Address(Z_method,    Method::const_offset()));
-  __ z_lg(Z_R1_scratch, Address(Z_R1_scratch, ConstMethod::constants_offset()));
+  // Load cp cache and save it at the end of this block.
+  __ z_lg(Z_R1_scratch, Address(const_method, ConstMethod::constants_offset()));
   __ z_lg(Z_R1_scratch, Address(Z_R1_scratch, ConstantPool::cache_offset_in_bytes()));
 
   // z_ijava_state->method = method;
@@ -1152,10 +1151,6 @@
   // parameters on top of caller's expression stack.
   // Tos points past last Java argument.
 
-  __ z_lg(Z_locals, Address(Z_method, Method::const_offset()));
-  __ z_llgh(Z_locals /*parameter_count words*/,
-            Address(Z_locals, ConstMethod::size_of_parameters_offset()));
-  __ z_sllg(Z_locals /*parameter_count bytes*/, Z_locals /*parameter_count*/, LogBytesPerWord);
   __ z_agr(Z_locals, Z_esp);
   // z_ijava_state->locals - i*BytesPerWord points to i-th Java local (i starts at 0)
   // z_ijava_state->locals = Z_esp + parameter_count bytes
@@ -1183,8 +1178,7 @@
   if (native_call) {
     __ clear_reg(Z_bcp); // Must initialize. Will get written into frame where GC reads it.
   } else {
-    __ z_lg(Z_bcp, method_(const));
-    __ add2reg(Z_bcp, in_bytes(ConstMethod::codes_offset()));
+    __ add2reg(Z_bcp, in_bytes(ConstMethod::codes_offset()), const_method);
   }
   __ z_stg(Z_bcp, _z_ijava_state_neg(bcp), fp);
 
@@ -1202,62 +1196,21 @@
   __ z_stg(Z_R1_scratch, _z_ijava_state_neg(cpoolCache), fp);
 
   // Get mirror and store it in the frame as GC root for this Method*.
-  __ load_mirror(Z_R1_scratch, Z_method);
+  __ load_mirror_from_const_method(Z_R1_scratch, const_method);
   __ z_stg(Z_R1_scratch, _z_ijava_state_neg(mirror), fp);
 
   BLOCK_COMMENT("} generate_fixed_frame: initialize interpreter state");
 
   //=============================================================================
   if (!native_call) {
-    // Fill locals with 0x0s.
-    NearLabel locals_zeroed;
-    NearLabel doXC;
-
     // Local_count is already num_locals_slots - num_param_slots.
-    __ compare64_and_branch(local_count, (intptr_t)0L, Assembler::bcondNotHigh, locals_zeroed);
-
-    // Advance local_addr to point behind locals (creates positive incr. in loop).
-    __ z_lg(Z_R1_scratch, Address(Z_method, Method::const_offset()));
-    __ z_llgh(Z_R0_scratch, Address(Z_R1_scratch, ConstMethod::size_of_locals_offset()));
-    __ add2reg(Z_R0_scratch, -1);
-
-    __ z_lgr(local_addr/*locals*/, Z_locals);
+    // Start of locals: local_addr = Z_locals - locals size + 1 slot
+    __ z_llgh(Z_R0_scratch, Address(const_method, ConstMethod::size_of_locals_offset()));
+    __ add2reg(local_addr, BytesPerWord, Z_locals);
     __ z_sllg(Z_R0_scratch, Z_R0_scratch, LogBytesPerWord);
-    __ z_sllg(local_count, local_count, LogBytesPerWord); // Local_count are non param locals.
     __ z_sgr(local_addr, Z_R0_scratch);
 
-    if (VM_Version::has_Prefetch()) {
-      __ z_pfd(0x02, 0, Z_R0, local_addr);
-      __ z_pfd(0x02, 256, Z_R0, local_addr);
-    }
-
-    // Can't optimise for Z10 using "compare and branch" (immediate value is too big).
-    __ z_cghi(local_count, 256);
-    __ z_brnh(doXC);
-
-    // MVCLE: Initialize if quite a lot locals.
-    //  __ bind(doMVCLE);
-    __ z_lgr(Z_R0_scratch, local_addr);
-    __ z_lgr(Z_R1_scratch, local_count);
-    __ clear_reg(Z_ARG2);        // Src len of MVCLE is zero.
-
-    __ MacroAssembler::move_long_ext(Z_R0_scratch, Z_ARG1, 0);
-    __ z_bru(locals_zeroed);
-
-    Label  XC_template;
-    __ bind(XC_template);
-    __ z_xc(0, 0, local_addr, 0, local_addr);
-
-    __ bind(doXC);
-    __ z_bctgr(local_count, Z_R0);                  // Get #bytes-1 for EXECUTE.
-    if (VM_Version::has_ExecuteExtensions()) {
-      __ z_exrl(local_count, XC_template);          // Execute XC with variable length.
-    } else {
-      __ z_larl(Z_R1_scratch, XC_template);
-      __ z_ex(local_count, 0, Z_R0, Z_R1_scratch);  // Execute XC with variable length.
-    }
-
-    __ bind(locals_zeroed);
+    __ Clear_Array(local_count, local_addr, Z_ARG2);
   }
 
   }
@@ -1530,8 +1483,8 @@
     Label method_is_not_static;
     __ testbit(method2_(Rmethod, access_flags), JVM_ACC_STATIC_BIT);
     __ z_bfalse(method_is_not_static);
-    // Get mirror.
-    __ load_mirror(Z_R1, Rmethod);
+    // Load mirror from interpreter frame.
+    __ z_lg(Z_R1, _z_ijava_state_neg(mirror), Z_fp);
     // z_ijava_state.oop_temp = pool_holder->klass_part()->java_mirror();
     __ z_stg(Z_R1, oop_tmp_offset, Z_fp);
     // Pass handle to mirror as 2nd argument to JNI method.
--- a/src/hotspot/cpu/s390/templateTable_s390.cpp	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/hotspot/cpu/s390/templateTable_s390.cpp	Thu Jun 13 11:31:36 2019 +0530
@@ -2404,14 +2404,14 @@
 // NOTE: Cpe_offset is already computed as byte offset, so we must not
 // shift it afterwards!
 void TemplateTable::resolve_cache_and_index(int byte_no,
-                                            Register Rcache,
+                                            Register cache,
                                             Register cpe_offset,
                                             size_t index_size) {
   BLOCK_COMMENT("resolve_cache_and_index {");
-  NearLabel      resolved;
+  NearLabel      resolved, clinit_barrier_slow;
   const Register bytecode_in_cpcache = Z_R1_scratch;
   const int      total_f1_offset = in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::f1_offset());
-  assert_different_registers(Rcache, cpe_offset, bytecode_in_cpcache);
+  assert_different_registers(cache, cpe_offset, bytecode_in_cpcache);
 
   Bytecodes::Code code = bytecode();
   switch (code) {
@@ -2423,19 +2423,32 @@
 
   {
     assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range");
-    __ get_cache_and_index_and_bytecode_at_bcp(Rcache, cpe_offset, bytecode_in_cpcache, byte_no, 1, index_size);
+    __ get_cache_and_index_and_bytecode_at_bcp(cache, cpe_offset, bytecode_in_cpcache, byte_no, 1, index_size);
     // Have we resolved this bytecode?
     __ compare32_and_branch(bytecode_in_cpcache, (int)code, Assembler::bcondEqual, resolved);
   }
 
   // Resolve first time through.
+  // Class initialization barrier slow path lands here as well.
+  __ bind(clinit_barrier_slow);
   address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache);
   __ load_const_optimized(Z_ARG2, (int) code);
   __ call_VM(noreg, entry, Z_ARG2);
 
   // Update registers with resolved info.
-  __ get_cache_and_index_at_bcp(Rcache, cpe_offset, 1, index_size);
+  __ get_cache_and_index_at_bcp(cache, cpe_offset, 1, index_size);
   __ bind(resolved);
+
+  // Class initialization barrier for static methods
+  if (VM_Version::supports_fast_class_init_checks() && bytecode() == Bytecodes::_invokestatic) {
+    const Register method = Z_R1_scratch;
+    const Register klass  = Z_R1_scratch;
+
+    __ load_resolved_method_at_index(byte_no, cache, cpe_offset, method);
+    __ load_method_holder(klass, method);
+    __ clinit_barrier(klass, Z_thread, NULL /*L_fast_path*/, &clinit_barrier_slow);
+  }
+
   BLOCK_COMMENT("} resolve_cache_and_index");
 }
 
@@ -3664,9 +3677,7 @@
   // Find entry point to call.
 
   // Get declaring interface class from method
-  __ z_lg(interface, Address(method, Method::const_offset()));
-  __ z_lg(interface, Address(interface, ConstMethod::constants_offset()));
-  __ z_lg(interface, Address(interface, ConstantPool::pool_holder_offset_in_bytes()));
+  __ load_method_holder(interface, method);
 
   // Get itable index from method
   Register index   = receiver,
--- a/src/hotspot/cpu/s390/vm_version_s390.hpp	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/hotspot/cpu/s390/vm_version_s390.hpp	Thu Jun 13 11:31:36 2019 +0530
@@ -349,6 +349,9 @@
   // Override Abstract_VM_Version implementation
   static void print_platform_virtualization_info(outputStream*);
 
+  // s390 supports fast class initialization checks for static methods.
+  static bool supports_fast_class_init_checks() { return true; }
+
   // CPU feature query functions
   static const char* get_model_string()       { return _model_string; }
   static bool has_StoreFacilityListExtended() { return  (_features[0] & StoreFacilityListExtendedMask) == StoreFacilityListExtendedMask; }
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp	Thu Jun 13 11:31:36 2019 +0530
@@ -4640,7 +4640,7 @@
 
   bool const during_im = collector_state()->in_initial_mark_gc();
   if (during_im && allocated_bytes > 0) {
-    _cm->root_regions()->add(alloc_region);
+    _cm->root_regions()->add(alloc_region->next_top_at_mark_start(), alloc_region->top());
   }
   _hr_printer.retire(alloc_region);
 }
--- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp	Thu Jun 13 11:31:36 2019 +0530
@@ -257,30 +257,38 @@
   _free_list = NULL;
 }
 
-G1CMRootRegions::G1CMRootRegions(uint const max_regions) :
-  _root_regions(NEW_C_HEAP_ARRAY(HeapRegion*, max_regions, mtGC)),
-  _max_regions(max_regions),
-  _num_root_regions(0),
-  _claimed_root_regions(0),
-  _scan_in_progress(false),
-  _should_abort(false) { }
-
-G1CMRootRegions::~G1CMRootRegions() {
-  FREE_C_HEAP_ARRAY(HeapRegion*, _max_regions);
+G1CMRootMemRegions::G1CMRootMemRegions(uint const max_regions) :
+    _root_regions(NULL),
+    _max_regions(max_regions),
+    _num_root_regions(0),
+    _claimed_root_regions(0),
+    _scan_in_progress(false),
+    _should_abort(false) {
+  _root_regions = new MemRegion[_max_regions];
+  if (_root_regions == NULL) {
+    vm_exit_during_initialization("Could not allocate root MemRegion set.");
+  }
 }
 
-void G1CMRootRegions::reset() {
+G1CMRootMemRegions::~G1CMRootMemRegions() {
+  delete[] _root_regions;
+}
+
+void G1CMRootMemRegions::reset() {
   _num_root_regions = 0;
 }
 
-void G1CMRootRegions::add(HeapRegion* hr) {
+void G1CMRootMemRegions::add(HeapWord* start, HeapWord* end) {
   assert_at_safepoint();
   size_t idx = Atomic::add((size_t)1, &_num_root_regions) - 1;
-  assert(idx < _max_regions, "Trying to add more root regions than there is space " SIZE_FORMAT, _max_regions);
-  _root_regions[idx] = hr;
+  assert(idx < _max_regions, "Trying to add more root MemRegions than there is space " SIZE_FORMAT, _max_regions);
+  assert(start != NULL && end != NULL && start <= end, "Start (" PTR_FORMAT ") should be less or equal to "
+         "end (" PTR_FORMAT ")", p2i(start), p2i(end));
+  _root_regions[idx].set_start(start);
+  _root_regions[idx].set_end(end);
 }
 
-void G1CMRootRegions::prepare_for_scan() {
+void G1CMRootMemRegions::prepare_for_scan() {
   assert(!scan_in_progress(), "pre-condition");
 
   _scan_in_progress = _num_root_regions > 0;
@@ -289,7 +297,7 @@
   _should_abort = false;
 }
 
-HeapRegion* G1CMRootRegions::claim_next() {
+const MemRegion* G1CMRootMemRegions::claim_next() {
   if (_should_abort) {
     // If someone has set the should_abort flag, we return NULL to
     // force the caller to bail out of their loop.
@@ -302,26 +310,26 @@
 
   size_t claimed_index = Atomic::add((size_t)1, &_claimed_root_regions) - 1;
   if (claimed_index < _num_root_regions) {
-    return _root_regions[claimed_index];
+    return &_root_regions[claimed_index];
   }
   return NULL;
 }
 
-uint G1CMRootRegions::num_root_regions() const {
+uint G1CMRootMemRegions::num_root_regions() const {
   return (uint)_num_root_regions;
 }
 
-void G1CMRootRegions::notify_scan_done() {
+void G1CMRootMemRegions::notify_scan_done() {
   MutexLocker x(RootRegionScan_lock, Mutex::_no_safepoint_check_flag);
   _scan_in_progress = false;
   RootRegionScan_lock->notify_all();
 }
 
-void G1CMRootRegions::cancel_scan() {
+void G1CMRootMemRegions::cancel_scan() {
   notify_scan_done();
 }
 
-void G1CMRootRegions::scan_finished() {
+void G1CMRootMemRegions::scan_finished() {
   assert(scan_in_progress(), "pre-condition");
 
   if (!_should_abort) {
@@ -333,7 +341,7 @@
   notify_scan_done();
 }
 
-bool G1CMRootRegions::wait_until_scan_finished() {
+bool G1CMRootMemRegions::wait_until_scan_finished() {
   if (!scan_in_progress()) {
     return false;
   }
@@ -875,14 +883,21 @@
   return result;
 }
 
-void G1ConcurrentMark::scan_root_region(HeapRegion* hr, uint worker_id) {
-  assert(hr->is_old() || (hr->is_survivor() && hr->next_top_at_mark_start() == hr->bottom()),
-         "Root regions must be old or survivor but region %u is %s", hr->hrm_index(), hr->get_type_str());
+void G1ConcurrentMark::scan_root_region(const MemRegion* region, uint worker_id) {
+#ifdef ASSERT
+  HeapWord* last = region->last();
+  HeapRegion* hr = _g1h->heap_region_containing(last);
+  assert(hr->is_old() || hr->next_top_at_mark_start() == hr->bottom(),
+         "Root regions must be old or survivor/eden but region %u is %s", hr->hrm_index(), hr->get_type_str());
+  assert(hr->next_top_at_mark_start() == region->start(),
+         "MemRegion start should be equal to nTAMS");
+#endif
+
   G1RootRegionScanClosure cl(_g1h, this, worker_id);
 
   const uintx interval = PrefetchScanIntervalInBytes;
-  HeapWord* curr = hr->next_top_at_mark_start();
-  const HeapWord* end = hr->top();
+  HeapWord* curr = region->start();
+  const HeapWord* end = region->end();
   while (curr < end) {
     Prefetch::read(curr, interval);
     oop obj = oop(curr);
@@ -902,11 +917,11 @@
     assert(Thread::current()->is_ConcurrentGC_thread(),
            "this should only be done by a conc GC thread");
 
-    G1CMRootRegions* root_regions = _cm->root_regions();
-    HeapRegion* hr = root_regions->claim_next();
-    while (hr != NULL) {
-      _cm->scan_root_region(hr, worker_id);
-      hr = root_regions->claim_next();
+    G1CMRootMemRegions* root_regions = _cm->root_regions();
+    const MemRegion* region = root_regions->claim_next();
+    while (region != NULL) {
+      _cm->scan_root_region(region, worker_id);
+      region = root_regions->claim_next();
     }
   }
 };
--- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp	Thu Jun 13 11:31:36 2019 +0530
@@ -222,18 +222,20 @@
   template<typename Fn> void iterate(Fn fn) const PRODUCT_RETURN;
 };
 
-// Root Regions are regions that contain objects from nTAMS to top. These are roots
-// for marking, i.e. their referenced objects must be kept alive to maintain the
+// Root MemRegions are memory areas that contain objects which references are
+// roots wrt to the marking. They must be scanned before marking to maintain the
 // SATB invariant.
-// We could scan and mark them through during the initial-mark pause, but for
+// Typically they contain the areas from nTAMS to top of the regions.
+// We could scan and mark through these objects during the initial-mark pause, but for
 // pause time reasons we move this work to the concurrent phase.
 // We need to complete this procedure before the next GC because it might determine
 // that some of these "root objects" are dead, potentially dropping some required
 // references.
-// Root regions comprise of the complete contents of survivor regions, and any
-// objects copied into old gen during GC.
-class G1CMRootRegions {
-  HeapRegion** _root_regions;
+// Root MemRegions comprise of the contents of survivor regions at the end
+// of the GC, and any objects copied into the old gen during GC.
+class G1CMRootMemRegions {
+  // The set of root MemRegions.
+  MemRegion*   _root_regions;
   size_t const _max_regions;
 
   volatile size_t _num_root_regions; // Actual number of root regions.
@@ -246,13 +248,13 @@
   void notify_scan_done();
 
 public:
-  G1CMRootRegions(uint const max_regions);
-  ~G1CMRootRegions();
+  G1CMRootMemRegions(uint const max_regions);
+  ~G1CMRootMemRegions();
 
   // Reset the data structure to allow addition of new root regions.
   void reset();
 
-  void add(HeapRegion* hr);
+  void add(HeapWord* start, HeapWord* end);
 
   // Reset the claiming / scanning of the root regions.
   void prepare_for_scan();
@@ -264,9 +266,9 @@
   // false otherwise.
   bool scan_in_progress() { return _scan_in_progress; }
 
-  // Claim the next root region to scan atomically, or return NULL if
+  // Claim the next root MemRegion to scan atomically, or return NULL if
   // all have been claimed.
-  HeapRegion* claim_next();
+  const MemRegion* claim_next();
 
   // The number of root regions to scan.
   uint num_root_regions() const;
@@ -310,7 +312,7 @@
   MemRegion const         _heap;
 
   // Root region tracking and claiming
-  G1CMRootRegions         _root_regions;
+  G1CMRootMemRegions         _root_regions;
 
   // For grey objects
   G1CMMarkStack           _global_mark_stack; // Grey objects behind global finger
@@ -501,7 +503,7 @@
   size_t partial_mark_stack_size_target() const { return _global_mark_stack.capacity() / 3; }
   bool mark_stack_empty() const                 { return _global_mark_stack.is_empty(); }
 
-  G1CMRootRegions* root_regions() { return &_root_regions; }
+  G1CMRootMemRegions* root_regions() { return &_root_regions; }
 
   void concurrent_cycle_start();
   // Abandon current marking iteration due to a Full GC.
@@ -554,8 +556,8 @@
   // them.
   void scan_root_regions();
 
-  // Scan a single root region from nTAMS to top and mark everything reachable from it.
-  void scan_root_region(HeapRegion* hr, uint worker_id);
+  // Scan a single root MemRegion to mark everything reachable from it.
+  void scan_root_region(const MemRegion* region, uint worker_id);
 
   // Do concurrent phase of marking, to a tentative transitive closure.
   void mark_from_roots();
--- a/src/hotspot/share/jvmci/jvmciEnv.cpp	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/hotspot/share/jvmci/jvmciEnv.cpp	Thu Jun 13 11:31:36 2019 +0530
@@ -1111,13 +1111,6 @@
   if (klass.is_null()) {
     return type;
   }
-#ifdef INCLUDE_ALL_GCS
-    if (UseG1GC) {
-      // The klass might have come from a weak location so enqueue
-      // the Class to make sure it's noticed by G1
-      G1SATBCardTableModRefBS::enqueue(klass()->java_mirror());
-    }
-#endif  // Klass* don't require tracking as Metadata*
 
   jlong pointer = (jlong) klass();
   JavaThread* THREAD = JavaThread::current();
--- a/src/hotspot/share/memory/memRegion.hpp	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/hotspot/share/memory/memRegion.hpp	Thu Jun 13 11:31:36 2019 +0530
@@ -32,13 +32,13 @@
 // A very simple data structure representing a contigous region
 // region of address space.
 
-// Note that MemRegions are passed by value, not by reference.
+// Note that MemRegions are typically passed by value, not by reference.
 // The intent is that they remain very small and contain no
 // objects. The copy constructor and destructor must be trivial,
 // to support optimization for pass-by-value.
-// These should never be allocated in heap but we do
-// create MemRegions (in CardTableBarrierSet) in heap so operator
-// new and operator new [] added for this special case.
+// These should almost never be allocated in heap but we do
+// create MemRegions (in CardTable and G1CMRootMemRegions) on the heap so operator
+// new and operator new [] were added for these special cases.
 
 class MemRegion {
   friend class VMStructs;
--- a/src/hotspot/share/memory/metaspace.cpp	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/hotspot/share/memory/metaspace.cpp	Thu Jun 13 11:31:36 2019 +0530
@@ -1221,7 +1221,7 @@
   }
 
   if (DynamicDumpSharedSpaces && !UseSharedSpaces) {
-    vm_exit_during_initialization("DynamicDumpSharedSpaces not supported when base CDS archive is not loaded", NULL);
+    vm_exit_during_initialization("DynamicDumpSharedSpaces is unsupported when base CDS archive is not loaded", NULL);
   }
 
   if (!DumpSharedSpaces && !UseSharedSpaces)
--- a/src/hotspot/share/opto/graphKit.hpp	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/hotspot/share/opto/graphKit.hpp	Thu Jun 13 11:31:36 2019 +0530
@@ -565,7 +565,7 @@
     return store_to_memory(ctl, adr, val, bt,
                            C->get_alias_index(adr_type),
                            mo, require_atomic_access,
-                           unaligned, mismatched);
+                           unaligned, mismatched, unsafe);
   }
   // This is the base version which is given alias index
   // Return the new StoreXNode
--- a/src/hotspot/share/opto/library_call.cpp	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/hotspot/share/opto/library_call.cpp	Thu Jun 13 11:31:36 2019 +0530
@@ -2439,7 +2439,10 @@
 
   val = is_store ? argument(4) : NULL;
 
-  const TypePtr *adr_type = _gvn.type(adr)->isa_ptr();
+  const TypePtr* adr_type = _gvn.type(adr)->isa_ptr();
+  if (adr_type == TypePtr::NULL_PTR) {
+    return false; // off-heap access with zero address
+  }
 
   // Try to categorize the address.
   Compile::AliasType* alias_type = C->alias_type(adr_type);
--- a/src/hotspot/share/opto/memnode.cpp	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/hotspot/share/opto/memnode.cpp	Thu Jun 13 11:31:36 2019 +0530
@@ -44,6 +44,7 @@
 #include "opto/narrowptrnode.hpp"
 #include "opto/phaseX.hpp"
 #include "opto/regmask.hpp"
+#include "opto/rootnode.hpp"
 #include "utilities/align.hpp"
 #include "utilities/copy.hpp"
 #include "utilities/macros.hpp"
@@ -328,6 +329,24 @@
   const Type *t_adr = phase->type(address);
   if (t_adr == Type::TOP)              return NodeSentinel; // caller will return NULL
 
+  if (can_reshape && is_unsafe_access() && (t_adr == TypePtr::NULL_PTR)) {
+    // Unsafe off-heap access with zero address. Remove access and other control users
+    // to not confuse optimizations and add a HaltNode to fail if this is ever executed.
+    assert(ctl != NULL, "unsafe accesses should be control dependent");
+    for (DUIterator_Fast imax, i = ctl->fast_outs(imax); i < imax; i++) {
+      Node* u = ctl->fast_out(i);
+      if (u != ctl) {
+        igvn->rehash_node_delayed(u);
+        int nb = u->replace_edge(ctl, phase->C->top());
+        --i, imax -= nb;
+      }
+    }
+    Node* frame = igvn->transform(new ParmNode(phase->C->start(), TypeFunc::FramePtr));
+    Node* halt = igvn->transform(new HaltNode(ctl, frame));
+    phase->C->root()->add_req(halt);
+    return this;
+  }
+
   if (can_reshape && igvn != NULL &&
       (igvn->_worklist.member(address) ||
        (igvn->_worklist.size() > 0 && t_adr != adr_type())) ) {
--- a/src/hotspot/share/opto/output.cpp	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/hotspot/share/opto/output.cpp	Thu Jun 13 11:31:36 2019 +0530
@@ -2412,12 +2412,9 @@
     }
     assert(!last->is_Mach() || last->as_Mach()->ideal_Opcode() != Op_Con, "");
     if( last->is_Catch() ||
-       // Exclude unreachable path case when Halt node is in a separate block.
-       (_bb_end > 1 && last->is_Mach() && last->as_Mach()->ideal_Opcode() == Op_Halt) ) {
-      // There must be a prior call.  Skip it.
-      while( !bb->get_node(--_bb_end)->is_MachCall() ) {
-        assert( bb->get_node(_bb_end)->is_MachProj(), "skipping projections after expected call" );
-      }
+       (last->is_Mach() && last->as_Mach()->ideal_Opcode() == Op_Halt) ) {
+      // There might be a prior call.  Skip it.
+      while (_bb_start < _bb_end && bb->get_node(--_bb_end)->is_MachProj());
     } else if( last->is_MachNullCheck() ) {
       // Backup so the last null-checked memory instruction is
       // outside the schedulable range. Skip over the nullcheck,
--- a/src/hotspot/share/runtime/objectMonitor.cpp	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/hotspot/share/runtime/objectMonitor.cpp	Thu Jun 13 11:31:36 2019 +0530
@@ -245,9 +245,7 @@
 
   void * cur = Atomic::cmpxchg(Self, &_owner, (void*)NULL);
   if (cur == NULL) {
-    // Either ASSERT _recursions == 0 or explicitly set _recursions = 0.
     assert(_recursions == 0, "invariant");
-    assert(_owner == Self, "invariant");
     return;
   }
 
@@ -405,9 +403,7 @@
   void * own = _owner;
   if (own != NULL) return 0;
   if (Atomic::replace_if_null(Self, &_owner)) {
-    // Either guarantee _recursions == 0 or set _recursions = 0.
     assert(_recursions == 0, "invariant");
-    assert(_owner == Self, "invariant");
     return 1;
   }
   // The lock had been free momentarily, but we lost the race to the lock.
@@ -417,6 +413,15 @@
   return -1;
 }
 
+// Convert the fields used by is_busy() to a string that can be
+// used for diagnostic output.
+const char* ObjectMonitor::is_busy_to_string(stringStream* ss) {
+  ss->print("is_busy: contentions=%d, waiters=%d, owner=" INTPTR_FORMAT
+            ", cxq=" INTPTR_FORMAT ", EntryList=" INTPTR_FORMAT, _contentions,
+            _waiters, p2i(_owner), p2i(_cxq), p2i(_EntryList));
+  return ss->base();
+}
+
 #define MAX_RECHECK_INTERVAL 1000
 
 void ObjectMonitor::EnterI(TRAPS) {
--- a/src/hotspot/share/runtime/objectMonitor.hpp	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/hotspot/share/runtime/objectMonitor.hpp	Thu Jun 13 11:31:36 2019 +0530
@@ -235,6 +235,7 @@
     // TODO-FIXME: assert _owner == null implies _recursions = 0
     return _contentions|_waiters|intptr_t(_owner)|intptr_t(_cxq)|intptr_t(_EntryList);
   }
+  const char* is_busy_to_string(stringStream* ss);
 
   intptr_t  is_entered(Thread* current) const;
 
@@ -268,7 +269,9 @@
     // _cxq == 0 _succ == NULL _owner == NULL _waiters == 0
     // _contentions == 0 EntryList  == NULL
     // _recursions == 0 _WaitSet == NULL
-    assert(((is_busy()|_recursions) == 0), "freeing inuse monitor");
+    DEBUG_ONLY(stringStream ss;)
+    assert((is_busy() | _recursions) == 0, "freeing in-use monitor: %s, "
+           "recursions=" INTPTR_FORMAT, is_busy_to_string(&ss), _recursions);
     _succ          = NULL;
     _EntryList     = NULL;
     _cxq           = NULL;
--- a/src/hotspot/share/runtime/objectMonitor.inline.hpp	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/hotspot/share/runtime/objectMonitor.inline.hpp	Thu Jun 13 11:31:36 2019 +0530
@@ -95,12 +95,8 @@
   return _contentions;
 }
 
-// Do NOT set _contentions = 0. There is a race such that _contentions could
-// be set while inflating prior to setting _owner
-// Just use Atomic::inc/dec and assert 0 when monitor put on free list
 inline void ObjectMonitor::set_owner(void* owner) {
   _owner = owner;
-  _recursions = 0;
 }
 
 #endif // SHARE_RUNTIME_OBJECTMONITOR_INLINE_HPP
--- a/src/hotspot/share/runtime/synchronizer.cpp	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/hotspot/share/runtime/synchronizer.cpp	Thu Jun 13 11:31:36 2019 +0530
@@ -242,7 +242,6 @@
 
     if (owner == NULL && Atomic::replace_if_null(Self, &(m->_owner))) {
       assert(m->_recursions == 0, "invariant");
-      assert(m->_owner == Self, "invariant");
       return true;
     }
   }
@@ -1030,6 +1029,7 @@
   // scavenge costs.  As usual, we lean toward time in space-time
   // tradeoffs.
   const int MAXPRIVATE = 1024;
+  stringStream ss;
   for (;;) {
     ObjectMonitor * m;
 
@@ -1065,7 +1065,6 @@
         ObjectMonitor * take = gFreeList;
         gFreeList = take->FreeNext;
         guarantee(take->object() == NULL, "invariant");
-        guarantee(!take->is_busy(), "invariant");
         take->Recycle();
         omRelease(Self, take, false);
       }
@@ -1167,7 +1166,10 @@
                                    bool fromPerThreadAlloc) {
   guarantee(m->header() == NULL, "invariant");
   guarantee(m->object() == NULL, "invariant");
-  guarantee(((m->is_busy()|m->_recursions) == 0), "freeing in-use monitor");
+  stringStream ss;
+  guarantee((m->is_busy() | m->_recursions) == 0, "freeing in-use monitor: "
+            "%s, recursions=" INTPTR_FORMAT, m->is_busy_to_string(&ss),
+            m->_recursions);
   // Remove from omInUseList
   if (fromPerThreadAlloc) {
     ObjectMonitor* cur_mid_in_use = NULL;
@@ -1220,16 +1222,14 @@
   int tally = 0;
   if (list != NULL) {
     ObjectMonitor * s;
-    // The thread is going away, the per-thread free monitors
-    // are freed via set_owner(NULL)
-    // Link them to tail, which will be linked into the global free list
-    // gFreeList below, under the gListLock
+    // The thread is going away. Set 'tail' to the last per-thread free
+    // monitor which will be linked to gFreeList below under the gListLock.
+    stringStream ss;
     for (s = list; s != NULL; s = s->FreeNext) {
       tally++;
       tail = s;
       guarantee(s->object() == NULL, "invariant");
-      guarantee(!s->is_busy(), "invariant");
-      s->set_owner(NULL);   // redundant but good hygiene
+      guarantee(!s->is_busy(), "must be !is_busy: %s", s->is_busy_to_string(&ss));
     }
     guarantee(tail != NULL, "invariant");
     assert(Self->omFreeCount == tally, "free-count off");
@@ -1379,7 +1379,6 @@
       // in which INFLATING appears in the mark.
       m->Recycle();
       m->_Responsible  = NULL;
-      m->_recursions   = 0;
       m->_SpinDuration = ObjectMonitor::Knob_SpinLimit;   // Consider: maintain by type/class
 
       markOop cmp = object->cas_set_mark(markOopDesc::INFLATING(), mark);
@@ -1472,9 +1471,7 @@
     // prepare m for installation - set monitor to initial state
     m->Recycle();
     m->set_header(mark);
-    m->set_owner(NULL);
     m->set_object(object);
-    m->_recursions   = 0;
     m->_Responsible  = NULL;
     m->_SpinDuration = ObjectMonitor::Knob_SpinLimit;       // consider: keep metastats by type/class
 
@@ -1925,14 +1922,15 @@
 // Check a free monitor entry; log any errors.
 void ObjectSynchronizer::chk_free_entry(JavaThread * jt, ObjectMonitor * n,
                                         outputStream * out, int *error_cnt_p) {
+  stringStream ss;
   if (n->is_busy()) {
     if (jt != NULL) {
       out->print_cr("ERROR: jt=" INTPTR_FORMAT ", monitor=" INTPTR_FORMAT
-                    ": free per-thread monitor must not be busy.", p2i(jt),
-                    p2i(n));
+                    ": free per-thread monitor must not be busy: %s", p2i(jt),
+                    p2i(n), n->is_busy_to_string(&ss));
     } else {
       out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": free global monitor "
-                    "must not be busy.", p2i(n));
+                    "must not be busy: %s", p2i(n), n->is_busy_to_string(&ss));
     }
     *error_cnt_p = *error_cnt_p + 1;
   }
@@ -2111,6 +2109,7 @@
     Thread::muxAcquire(&gListLock, "log_in_use_monitor_details");
   }
 
+  stringStream ss;
   if (gOmInUseCount > 0) {
     out->print_cr("In-use global monitor info:");
     out->print_cr("(B -> is_busy, H -> has hash code, L -> lock status)");
@@ -2121,9 +2120,14 @@
       const oop obj = (oop) n->object();
       const markOop mark = n->header();
       ResourceMark rm;
-      out->print_cr(INTPTR_FORMAT "  %d%d%d  " INTPTR_FORMAT "  %s", p2i(n),
-                    n->is_busy() != 0, mark->hash() != 0, n->owner() != NULL,
-                    p2i(obj), obj->klass()->external_name());
+      out->print(INTPTR_FORMAT "  %d%d%d  " INTPTR_FORMAT "  %s", p2i(n),
+                 n->is_busy() != 0, mark->hash() != 0, n->owner() != NULL,
+                 p2i(obj), obj->klass()->external_name());
+      if (n->is_busy() != 0) {
+        out->print(" (%s)", n->is_busy_to_string(&ss));
+        ss.reset();
+      }
+      out->cr();
     }
   }
 
@@ -2141,10 +2145,15 @@
       const oop obj = (oop) n->object();
       const markOop mark = n->header();
       ResourceMark rm;
-      out->print_cr(INTPTR_FORMAT "  " INTPTR_FORMAT "  %d%d%d  " INTPTR_FORMAT
-                    "  %s", p2i(jt), p2i(n), n->is_busy() != 0,
-                    mark->hash() != 0, n->owner() != NULL, p2i(obj),
-                    obj->klass()->external_name());
+      out->print(INTPTR_FORMAT "  " INTPTR_FORMAT "  %d%d%d  " INTPTR_FORMAT
+                 "  %s", p2i(jt), p2i(n), n->is_busy() != 0,
+                 mark->hash() != 0, n->owner() != NULL, p2i(obj),
+                 obj->klass()->external_name());
+      if (n->is_busy() != 0) {
+        out->print(" (%s)", n->is_busy_to_string(&ss));
+        ss.reset();
+      }
+      out->cr();
     }
   }
 
--- a/src/java.base/share/classes/java/lang/ref/Reference.java	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/java.base/share/classes/java/lang/ref/Reference.java	Thu Jun 13 11:31:36 2019 +0530
@@ -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
@@ -418,10 +418,10 @@
      * {@code synchronized} blocks or methods, or using other synchronization
      * facilities are not possible or do not provide the desired control.  This
      * method is applicable only when reclamation may have visible effects,
-     * which is possible for objects with finalizers (See
-     * <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.6">
-     * Section 12.6 17 of <cite>The Java&trade; Language Specification</cite></a>)
-     * that are implemented in ways that rely on ordering control for correctness.
+     * which is possible for objects with finalizers (See Section 12.6
+     * of <cite>The Java&trade; Language Specification</cite>) that
+     * are implemented in ways that rely on ordering control for
+     * correctness.
      *
      * @apiNote
      * Finalization may occur whenever the virtual machine detects that no
@@ -508,6 +508,7 @@
      *
      * @param ref the reference. If {@code null}, this method has no effect.
      * @since 9
+     * @jls 12.6 Finalization of Class Instances
      */
     @ForceInline
     public static void reachabilityFence(Object ref) {
--- a/src/java.base/share/classes/java/net/SocketImpl.java	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/java.base/share/classes/java/net/SocketImpl.java	Thu Jun 13 11:31:36 2019 +0530
@@ -396,7 +396,7 @@
      *
      * @implSpec
      * The default implementation of this method first checks that the given
-     * socket option {code name} is not null, then throws {@code
+     * socket option {@code name} is not null, then throws {@code
      * UnsupportedOperationException}. Subclasses should override this method
      * with an appropriate implementation.
      *
@@ -424,7 +424,7 @@
      *
      * @implSpec
      * The default implementation of this method first checks that the given
-     * socket option {code name} is not null, then throws {@code
+     * socket option {@code name} is not null, then throws {@code
      * UnsupportedOperationException}. Subclasses should override this method
      * with an appropriate implementation.
      *
--- a/src/java.base/share/classes/sun/security/ssl/CipherSuite.java	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/java.base/share/classes/sun/security/ssl/CipherSuite.java	Thu Jun 13 11:31:36 2019 +0530
@@ -35,8 +35,8 @@
 import static sun.security.ssl.CipherSuite.KeyExchange.*;
 import static sun.security.ssl.CipherSuite.MacAlg.*;
 import static sun.security.ssl.SSLCipher.*;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroupType;
-import static sun.security.ssl.SupportedGroupsExtension.NamedGroupType.*;
+import sun.security.ssl.NamedGroup.NamedGroupType;
+import static sun.security.ssl.NamedGroup.NamedGroupType.*;
 
 /**
  * Enum for SSL/(D)TLS cipher suites.
@@ -184,7 +184,7 @@
             K_DHE_DSS, B_AES_128, M_SHA256, H_SHA256),
 
     //
-    // not forward screcy cipher suites.
+    // not forward secret cipher suites.
     //
 
     // AES_256(GCM)
@@ -1106,11 +1106,18 @@
         K_DH_ANON       ("DH_anon",        true,  true,   NAMED_GROUP_FFDHE),
         K_DH_ANON_EXPORT("DH_anon_EXPORT", true,  true,   NAMED_GROUP_NONE),
 
-        K_ECDH_ECDSA    ("ECDH_ECDSA",     true,  false,  NAMED_GROUP_ECDHE),
-        K_ECDH_RSA      ("ECDH_RSA",       true,  false,  NAMED_GROUP_ECDHE),
-        K_ECDHE_ECDSA   ("ECDHE_ECDSA",    true,  false,  NAMED_GROUP_ECDHE),
-        K_ECDHE_RSA     ("ECDHE_RSA",      true,  false,  NAMED_GROUP_ECDHE),
-        K_ECDH_ANON     ("ECDH_anon",      true,  true,   NAMED_GROUP_ECDHE),
+        // These KeyExchanges can use either ECDHE/XDH, so we'll use a
+        // varargs here.
+        K_ECDH_ECDSA    ("ECDH_ECDSA",     JsseJce.ALLOW_ECC,  false,
+                NAMED_GROUP_ECDHE, NAMED_GROUP_XDH),
+        K_ECDH_RSA      ("ECDH_RSA",       JsseJce.ALLOW_ECC,  false,
+            NAMED_GROUP_ECDHE, NAMED_GROUP_XDH),
+        K_ECDHE_ECDSA   ("ECDHE_ECDSA",    JsseJce.ALLOW_ECC,  false,
+            NAMED_GROUP_ECDHE, NAMED_GROUP_XDH),
+        K_ECDHE_RSA     ("ECDHE_RSA",      JsseJce.ALLOW_ECC,  false,
+            NAMED_GROUP_ECDHE, NAMED_GROUP_XDH),
+        K_ECDH_ANON     ("ECDH_anon",      JsseJce.ALLOW_ECC,  true,
+            NAMED_GROUP_ECDHE, NAMED_GROUP_XDH),
 
         // renegotiation protection request signaling cipher suite
         K_SCSV          ("SCSV",           true,  true,   NAMED_GROUP_NONE);
@@ -1118,19 +1125,16 @@
         // name of the key exchange algorithm, e.g. DHE_DSS
         final String name;
         final boolean allowed;
-        final NamedGroupType groupType;
+        final NamedGroupType[] groupTypes;
         private final boolean alwaysAvailable;
         private final boolean isAnonymous;
 
         KeyExchange(String name, boolean allowed,
-                boolean isAnonymous, NamedGroupType groupType) {
+                boolean isAnonymous, NamedGroupType... groupTypes) {
             this.name = name;
-            if (groupType == NAMED_GROUP_ECDHE) {
-                this.allowed = JsseJce.ALLOW_ECC;
-            } else {
-                this.allowed = allowed;
-            }
-            this.groupType = groupType;
+            this.groupTypes = groupTypes;
+            this.allowed = allowed;
+
             this.alwaysAvailable = allowed && (!name.startsWith("EC"));
             this.isAnonymous = isAnonymous;
         }
@@ -1140,7 +1144,8 @@
                 return true;
             }
 
-            if (groupType == NAMED_GROUP_ECDHE) {
+            if (NamedGroupType.arrayContains(
+                    groupTypes, NamedGroupType.NAMED_GROUP_ECDHE)) {
                 return (allowed && JsseJce.isEcAvailable());
             } else {
                 return allowed;
--- a/src/java.base/share/classes/sun/security/ssl/DHClientKeyExchange.java	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/java.base/share/classes/sun/security/ssl/DHClientKeyExchange.java	Thu Jun 13 11:31:36 2019 +0530
@@ -42,7 +42,6 @@
 import sun.security.ssl.DHKeyExchange.DHECredentials;
 import sun.security.ssl.DHKeyExchange.DHEPossession;
 import sun.security.ssl.SSLHandshake.HandshakeMessage;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
 import sun.security.util.HexDumpEncoder;
 
 /**
--- a/src/java.base/share/classes/sun/security/ssl/DHKeyExchange.java	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/java.base/share/classes/sun/security/ssl/DHKeyExchange.java	Thu Jun 13 11:31:36 2019 +0530
@@ -36,19 +36,12 @@
 import java.security.PrivateKey;
 import java.security.PublicKey;
 import java.security.SecureRandom;
-import java.security.spec.AlgorithmParameterSpec;
 import java.security.spec.InvalidKeySpecException;
-import javax.crypto.KeyAgreement;
-import javax.crypto.SecretKey;
 import javax.crypto.interfaces.DHPublicKey;
 import javax.crypto.spec.DHParameterSpec;
 import javax.crypto.spec.DHPublicKeySpec;
-import javax.crypto.spec.SecretKeySpec;
-import javax.net.ssl.SSLHandshakeException;
 import sun.security.action.GetPropertyAction;
-import sun.security.ssl.CipherSuite.HashAlg;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroupType;
+import sun.security.ssl.NamedGroup.NamedGroupType;
 import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
 import sun.security.ssl.X509Authentication.X509Possession;
 import sun.security.util.KeyUtil;
@@ -61,7 +54,7 @@
     static final SSLKeyAgreementGenerator kaGenerator =
             new DHEKAGenerator();
 
-    static final class DHECredentials implements SSLCredentials {
+    static final class DHECredentials implements NamedGroupCredentials {
         final DHPublicKey popPublicKey;
         final NamedGroup namedGroup;
 
@@ -70,6 +63,16 @@
             this.namedGroup = namedGroup;
         }
 
+        @Override
+        public PublicKey getPublicKey() {
+            return popPublicKey;
+        }
+
+        @Override
+        public NamedGroup getNamedGroup() {
+            return namedGroup;
+        }
+
         static DHECredentials valueOf(NamedGroup ng,
             byte[] encodedPublic) throws IOException, GeneralSecurityException {
 
@@ -98,7 +101,7 @@
         }
     }
 
-    static final class DHEPossession implements SSLPossession {
+    static final class DHEPossession implements NamedGroupPossession {
         final PrivateKey privateKey;
         final DHPublicKey publicKey;
         final NamedGroup namedGroup;
@@ -174,13 +177,13 @@
         // Generate and validate DHPublicKeySpec
         private KeyPair generateDHKeyPair(
                 KeyPairGenerator kpg) throws GeneralSecurityException {
-            boolean doExtraValiadtion =
+            boolean doExtraValidation =
                     (!KeyUtil.isOracleJCEProvider(kpg.getProvider().getName()));
             boolean isRecovering = false;
             for (int i = 0; i <= 2; i++) {      // Try to recover from failure.
                 KeyPair kp = kpg.generateKeyPair();
                 // validate the Diffie-Hellman public key
-                if (doExtraValiadtion) {
+                if (doExtraValidation) {
                     DHPublicKeySpec spec = getDHPublicKeySpec(kp.getPublic());
                     try {
                         KeyUtil.validate(spec);
@@ -231,6 +234,21 @@
 
             return encoded;
         }
+
+        @Override
+        public PublicKey getPublicKey() {
+            return publicKey;
+        }
+
+        @Override
+        public NamedGroup getNamedGroup() {
+            return namedGroup;
+        }
+
+        @Override
+        public PrivateKey getPrivateKey() {
+            return privateKey;
+        }
     }
 
     private static final class
@@ -298,7 +316,7 @@
         // Used for ServerKeyExchange, TLS 1.2 and prior versions.
         @Override
         public SSLPossession createPossession(HandshakeContext context) {
-            NamedGroup preferableNamedGroup = null;
+            NamedGroup preferableNamedGroup;
             if (!useLegacyEphemeralDHKeys &&
                     (context.clientRequestedNamedGroups != null) &&
                     (!context.clientRequestedNamedGroups.isEmpty())) {
@@ -306,7 +324,8 @@
                         SupportedGroups.getPreferredGroup(
                                 context.negotiatedProtocol,
                                 context.algorithmConstraints,
-                                NamedGroupType.NAMED_GROUP_FFDHE,
+                                new NamedGroupType [] {
+                                    NamedGroupType.NAMED_GROUP_FFDHE },
                                 context.clientRequestedNamedGroups);
                 if (preferableNamedGroup != null) {
                     return new DHEPossession(preferableNamedGroup,
@@ -392,7 +411,7 @@
 
     private static final
             class DHEKAGenerator implements SSLKeyAgreementGenerator {
-        static private DHEKAGenerator instance = new DHEKAGenerator();
+        private static final DHEKAGenerator instance = new DHEKAGenerator();
 
         // Prevent instantiation of this class.
         private DHEKAGenerator() {
@@ -442,93 +461,8 @@
                     "No sufficient DHE key agreement parameters negotiated");
             }
 
-            return new DHEKAKeyDerivation(context,
+            return new KAKeyDerivation("DiffieHellman", context,
                     dhePossession.privateKey, dheCredentials.popPublicKey);
         }
-
-        private static final
-                class DHEKAKeyDerivation implements SSLKeyDerivation {
-            private final HandshakeContext context;
-            private final PrivateKey localPrivateKey;
-            private final PublicKey peerPublicKey;
-
-            DHEKAKeyDerivation(HandshakeContext context,
-                    PrivateKey localPrivateKey,
-                    PublicKey peerPublicKey) {
-                this.context = context;
-                this.localPrivateKey = localPrivateKey;
-                this.peerPublicKey = peerPublicKey;
-            }
-
-            @Override
-            public SecretKey deriveKey(String algorithm,
-                    AlgorithmParameterSpec params) throws IOException {
-                if (!context.negotiatedProtocol.useTLS13PlusSpec()) {
-                    return t12DeriveKey(algorithm, params);
-                } else {
-                    return t13DeriveKey(algorithm, params);
-                }
-            }
-
-            private SecretKey t12DeriveKey(String algorithm,
-                    AlgorithmParameterSpec params) throws IOException {
-                try {
-                    KeyAgreement ka = KeyAgreement.getInstance("DiffieHellman");
-                    ka.init(localPrivateKey);
-                    ka.doPhase(peerPublicKey, true);
-                    SecretKey preMasterSecret =
-                            ka.generateSecret("TlsPremasterSecret");
-                    SSLMasterKeyDerivation mskd =
-                            SSLMasterKeyDerivation.valueOf(
-                                    context.negotiatedProtocol);
-                    if (mskd == null) {
-                        // unlikely
-                        throw new SSLHandshakeException(
-                            "No expected master key derivation for protocol: " +
-                            context.negotiatedProtocol.name);
-                    }
-                    SSLKeyDerivation kd = mskd.createKeyDerivation(
-                            context, preMasterSecret);
-                    return kd.deriveKey("MasterSecret", params);
-                } catch (GeneralSecurityException gse) {
-                    throw (SSLHandshakeException) new SSLHandshakeException(
-                        "Could not generate secret").initCause(gse);
-                }
-            }
-
-            private SecretKey t13DeriveKey(String algorithm,
-                    AlgorithmParameterSpec params) throws IOException {
-                try {
-                    KeyAgreement ka = KeyAgreement.getInstance("DiffieHellman");
-                    ka.init(localPrivateKey);
-                    ka.doPhase(peerPublicKey, true);
-                    SecretKey sharedSecret =
-                            ka.generateSecret("TlsPremasterSecret");
-
-                    HashAlg hashAlg = context.negotiatedCipherSuite.hashAlg;
-                    SSLKeyDerivation kd = context.handshakeKeyDerivation;
-                    HKDF hkdf = new HKDF(hashAlg.name);
-                    if (kd == null) {   // No PSK is in use.
-                        // If PSK is not in use Early Secret will still be
-                        // HKDF-Extract(0, 0).
-                        byte[] zeros = new byte[hashAlg.hashLength];
-                        SecretKeySpec ikm =
-                                new SecretKeySpec(zeros, "TlsPreSharedSecret");
-                        SecretKey earlySecret =
-                                hkdf.extract(zeros, ikm, "TlsEarlySecret");
-                        kd = new SSLSecretDerivation(context, earlySecret);
-                    }
-
-                    // derive salt secret
-                    SecretKey saltSecret = kd.deriveKey("TlsSaltSecret", null);
-
-                    // derive handshake secret
-                    return hkdf.extract(saltSecret, sharedSecret, algorithm);
-                } catch (GeneralSecurityException gse) {
-                    throw (SSLHandshakeException) new SSLHandshakeException(
-                        "Could not generate secret").initCause(gse);
-                }
-            }
-        }
     }
 }
--- a/src/java.base/share/classes/sun/security/ssl/DHServerKeyExchange.java	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/java.base/share/classes/sun/security/ssl/DHServerKeyExchange.java	Thu Jun 13 11:31:36 2019 +0530
@@ -48,7 +48,6 @@
 import sun.security.ssl.DHKeyExchange.DHECredentials;
 import sun.security.ssl.DHKeyExchange.DHEPossession;
 import sun.security.ssl.SSLHandshake.HandshakeMessage;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
 import sun.security.ssl.X509Authentication.X509Credentials;
 import sun.security.ssl.X509Authentication.X509Possession;
 import sun.security.util.HexDumpEncoder;
--- a/src/java.base/share/classes/sun/security/ssl/ECDHClientKeyExchange.java	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/java.base/share/classes/sun/security/ssl/ECDHClientKeyExchange.java	Thu Jun 13 11:31:36 2019 +0530
@@ -27,31 +27,28 @@
 
 import java.io.IOException;
 import java.nio.ByteBuffer;
-import java.security.AlgorithmConstraints;
-import java.security.CryptoPrimitive;
 import java.security.GeneralSecurityException;
-import java.security.KeyFactory;
 import java.security.PublicKey;
 import java.security.interfaces.ECPublicKey;
+import java.security.interfaces.XECPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
 import java.security.spec.ECParameterSpec;
-import java.security.spec.ECPoint;
-import java.security.spec.ECPublicKeySpec;
+import java.security.spec.NamedParameterSpec;
 import java.text.MessageFormat;
-import java.util.EnumSet;
 import java.util.Locale;
 import javax.crypto.SecretKey;
-import javax.net.ssl.SSLHandshakeException;
-import sun.security.ssl.ECDHKeyExchange.ECDHECredentials;
-import sun.security.ssl.ECDHKeyExchange.ECDHEPossession;
 import sun.security.ssl.SSLHandshake.HandshakeMessage;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
 import sun.security.ssl.X509Authentication.X509Credentials;
 import sun.security.ssl.X509Authentication.X509Possession;
-import sun.security.util.ECUtil;
 import sun.security.util.HexDumpEncoder;
 
 /**
  * Pack of the "ClientKeyExchange" handshake message.
+ *
+ * This file is used by both the ECDH/ECDHE/XDH code since much of the
+ * code is the same between the EC named groups (i.e.
+ * x25519/x448/secp*r1), even though the APIs are very different (i.e.
+ * ECPublicKey/XECPublicKey, KeyExchange.getInstance("EC"/"XDH"), etc.).
  */
 final class ECDHClientKeyExchange {
     static final SSLConsumer ecdhHandshakeConsumer =
@@ -65,19 +62,17 @@
             new ECDHEClientKeyExchangeProducer();
 
     /**
-     * The ECDH/ECDHE ClientKeyExchange handshake message.
+     * The ECDH/ECDHE/XDH ClientKeyExchange handshake message.
      */
     private static final
             class ECDHClientKeyExchangeMessage extends HandshakeMessage {
         private final byte[] encodedPoint;
 
         ECDHClientKeyExchangeMessage(HandshakeContext handshakeContext,
-                ECPublicKey publicKey) {
+                byte[] encodedPublicKey) {
             super(handshakeContext);
 
-            ECPoint point = publicKey.getW();
-            ECParameterSpec params = publicKey.getParams();
-            encodedPoint = ECUtil.encodePoint(point, params.getCurve());
+            this.encodedPoint = encodedPublicKey;
         }
 
         ECDHClientKeyExchangeMessage(HandshakeContext handshakeContext,
@@ -90,34 +85,6 @@
             }
         }
 
-        // Check constraints of the specified EC public key.
-        static void checkConstraints(AlgorithmConstraints constraints,
-                ECPublicKey publicKey,
-                byte[] encodedPoint) throws SSLHandshakeException {
-
-            try {
-                ECParameterSpec params = publicKey.getParams();
-                ECPoint point =
-                        ECUtil.decodePoint(encodedPoint, params.getCurve());
-                ECPublicKeySpec spec = new ECPublicKeySpec(point, params);
-
-                KeyFactory kf = KeyFactory.getInstance("EC");
-                ECPublicKey peerPublicKey =
-                        (ECPublicKey)kf.generatePublic(spec);
-
-                // check constraints of ECPublicKey
-                if (!constraints.permits(
-                        EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
-                        peerPublicKey)) {
-                    throw new SSLHandshakeException(
-                        "ECPublicKey does not comply to algorithm constraints");
-                }
-            } catch (GeneralSecurityException | java.io.IOException e) {
-                throw (SSLHandshakeException) new SSLHandshakeException(
-                        "Could not generate ECPublicKey").initCause(e);
-            }
-        }
-
         @Override
         public SSLHandshake handshakeType() {
             return SSLHandshake.CLIENT_KEY_EXCHANGE;
@@ -194,24 +161,41 @@
             }
 
             PublicKey publicKey = x509Credentials.popPublicKey;
-            if (!publicKey.getAlgorithm().equals("EC")) {
+
+            NamedGroup namedGroup = null;
+            String algorithm = publicKey.getAlgorithm();
+
+            // Determine which NamedGroup we'll be using, then use
+            // the creator functions.
+            if (algorithm.equals("EC")) {
+                ECParameterSpec params = ((ECPublicKey)publicKey).getParams();
+                namedGroup = NamedGroup.valueOf(params);
+            } else if (algorithm.equals("XDH")) {
+                AlgorithmParameterSpec params =
+                        ((XECPublicKey)publicKey).getParams();
+                if (params instanceof NamedParameterSpec) {
+                    String name = ((NamedParameterSpec)params).getName();
+                    namedGroup = NamedGroup.nameOf(name);
+                }
+            } else {
                 throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
-                    "Not EC server certificate for ECDH client key exchange");
+                    "Not EC/XDH server certificate for " +
+                            "ECDH client key exchange");
             }
 
-            ECParameterSpec params = ((ECPublicKey)publicKey).getParams();
-            NamedGroup namedGroup = NamedGroup.valueOf(params);
             if (namedGroup == null) {
                 throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
-                    "Unsupported EC server cert for ECDH client key exchange");
+                    "Unsupported EC/XDH server cert for " +
+                        "ECDH client key exchange");
             }
 
-            ECDHEPossession ecdhePossession = new ECDHEPossession(
-                    namedGroup, chc.sslContext.getSecureRandom());
-            chc.handshakePossessions.add(ecdhePossession);
+            SSLPossession sslPossession = namedGroup.createPossession(
+                    chc.sslContext.getSecureRandom());
+
+            chc.handshakePossessions.add(sslPossession);
             ECDHClientKeyExchangeMessage cke =
                     new ECDHClientKeyExchangeMessage(
-                            chc, ecdhePossession.publicKey);
+                            chc, sslPossession.encode());
             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
                 SSLLogger.fine(
                     "Produced ECDH ClientKeyExchange handshake message", cke);
@@ -283,18 +267,35 @@
                     "No expected EC server cert for ECDH client key exchange");
             }
 
-            ECParameterSpec params = x509Possession.getECParameterSpec();
-            if (params == null) {
+            // Determine which NamedGroup we'll be using, then use
+            // the creator functions.
+            NamedGroup namedGroup = null;
+
+            // Iteratively determine the X509Possession type's ParameterSpec.
+            ECParameterSpec ecParams = x509Possession.getECParameterSpec();
+            NamedParameterSpec namedParams = null;
+            if (ecParams != null) {
+                namedGroup = NamedGroup.valueOf(ecParams);
+            }
+
+            // Wasn't EC, try XEC.
+            if (ecParams == null) {
+                namedParams = x509Possession.getXECParameterSpec();
+                namedGroup = NamedGroup.nameOf(namedParams.getName());
+            }
+
+            // Can't figure this out, bail.
+            if ((ecParams == null) && (namedParams == null)) {
                 // unlikely, have been checked during cipher suite negotiation.
                 throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
-                    "Not EC server cert for ECDH client key exchange");
+                    "Not EC/XDH server cert for ECDH client key exchange");
             }
 
-            NamedGroup namedGroup = NamedGroup.valueOf(params);
+            // unlikely, have been checked during cipher suite negotiation.
             if (namedGroup == null) {
-                // unlikely, have been checked during cipher suite negotiation.
                 throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
-                    "Unsupported EC server cert for ECDH client key exchange");
+                    "Unknown named group in server cert for " +
+                        "ECDH client key exchange");
             }
 
             SSLKeyExchange ke = SSLKeyExchange.valueOf(
@@ -306,7 +307,7 @@
                         "Not supported key exchange type");
             }
 
-            // parse the handshake message
+            // parse either handshake message containing either EC/XEC.
             ECDHClientKeyExchangeMessage cke =
                     new ECDHClientKeyExchangeMessage(shc, message);
             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
@@ -316,27 +317,17 @@
 
             // create the credentials
             try {
-                ECPoint point =
-                    ECUtil.decodePoint(cke.encodedPoint, params.getCurve());
-                ECPublicKeySpec spec = new ECPublicKeySpec(point, params);
+                NamedGroup ng = namedGroup;  // "effectively final" the lambda
+                // AlgorithmConstraints are checked internally.
+                SSLCredentials sslCredentials = namedGroup.decodeCredentials(
+                        cke.encodedPoint, shc.algorithmConstraints,
+                        s -> shc.conContext.fatal(Alert.INSUFFICIENT_SECURITY,
+                        "ClientKeyExchange " + ng + ": " + s));
 
-                KeyFactory kf = KeyFactory.getInstance("EC");
-                ECPublicKey peerPublicKey =
-                        (ECPublicKey)kf.generatePublic(spec);
-
-                // check constraints of peer ECPublicKey
-                if (!shc.algorithmConstraints.permits(
-                        EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
-                        peerPublicKey)) {
-                    throw new SSLHandshakeException(
-                        "ECPublicKey does not comply to algorithm constraints");
-                }
-
-                shc.handshakeCredentials.add(new ECDHECredentials(
-                        peerPublicKey, namedGroup));
-            } catch (GeneralSecurityException | java.io.IOException e) {
-                throw (SSLHandshakeException)(new SSLHandshakeException(
-                        "Could not generate ECPublicKey").initCause(e));
+                shc.handshakeCredentials.add(sslCredentials);
+            } catch (GeneralSecurityException e) {
+                throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
+                        "Cannot decode ECDH PublicKey: " + namedGroup);
             }
 
             // update the states
@@ -374,25 +365,37 @@
             // The producing happens in client side only.
             ClientHandshakeContext chc = (ClientHandshakeContext)context;
 
-            ECDHECredentials ecdheCredentials = null;
+            SSLCredentials sslCredentials = null;
+            NamedGroup ng = null;
+            PublicKey publicKey = null;
+
+            // Find a good EC/XEC credential to use, determine the
+            // NamedGroup to use for creating Possessions/Credentials/Keys.
             for (SSLCredentials cd : chc.handshakeCredentials) {
-                if (cd instanceof ECDHECredentials) {
-                    ecdheCredentials = (ECDHECredentials)cd;
+                if (cd instanceof NamedGroupCredentials) {
+                    NamedGroupCredentials creds = (NamedGroupCredentials)cd;
+                    ng = creds.getNamedGroup();
+                    publicKey = creds.getPublicKey();
+                    sslCredentials = cd;
                     break;
                 }
             }
 
-            if (ecdheCredentials == null) {
+            if (sslCredentials == null) {
                 throw chc.conContext.fatal(Alert.INTERNAL_ERROR,
                     "No ECDHE credentials negotiated for client key exchange");
             }
 
-            ECDHEPossession ecdhePossession = new ECDHEPossession(
-                    ecdheCredentials, chc.sslContext.getSecureRandom());
-            chc.handshakePossessions.add(ecdhePossession);
+            SSLPossession sslPossession = ng.createPossession(
+                    chc.sslContext.getSecureRandom());
+
+            chc.handshakePossessions.add(sslPossession);
+
+            // Write the EC/XEC message.
             ECDHClientKeyExchangeMessage cke =
                     new ECDHClientKeyExchangeMessage(
-                            chc, ecdhePossession.publicKey);
+                            chc, sslPossession.encode());
+
             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
                 SSLLogger.fine(
                     "Produced ECDHE ClientKeyExchange handshake message", cke);
@@ -450,23 +453,29 @@
             // The consuming happens in server side only.
             ServerHandshakeContext shc = (ServerHandshakeContext)context;
 
-            ECDHEPossession ecdhePossession = null;
+            SSLPossession sslPossession = null;
+            NamedGroup namedGroup = null;
+
+           // Find a good EC/XEC credential to use, determine the
+           // NamedGroup to use for creating Possessions/Credentials/Keys.
             for (SSLPossession possession : shc.handshakePossessions) {
-                if (possession instanceof ECDHEPossession) {
-                    ecdhePossession = (ECDHEPossession)possession;
+                if (possession instanceof NamedGroupPossession) {
+                    NamedGroupPossession poss =
+                            (NamedGroupPossession)possession;
+                    namedGroup = poss.getNamedGroup();
+                    sslPossession = poss;
                     break;
                 }
             }
-            if (ecdhePossession == null) {
+
+            if (sslPossession == null) {
                 // unlikely
                 throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
                     "No expected ECDHE possessions for client key exchange");
             }
 
-            ECParameterSpec params = ecdhePossession.publicKey.getParams();
-            NamedGroup namedGroup = NamedGroup.valueOf(params);
             if (namedGroup == null) {
-                // unlikely, have been checked during cipher suite negotiation.
+                // unlikely, have been checked during cipher suite negotiation
                 throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
                     "Unsupported EC server cert for ECDHE client key exchange");
             }
@@ -480,7 +489,7 @@
                         "Not supported key exchange type");
             }
 
-            // parse the handshake message
+            // parse the EC/XEC handshake message
             ECDHClientKeyExchangeMessage cke =
                     new ECDHClientKeyExchangeMessage(shc, message);
             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
@@ -490,27 +499,17 @@
 
             // create the credentials
             try {
-                ECPoint point =
-                    ECUtil.decodePoint(cke.encodedPoint, params.getCurve());
-                ECPublicKeySpec spec = new ECPublicKeySpec(point, params);
+                NamedGroup ng = namedGroup; // "effectively final" the lambda
+                // AlgorithmConstraints are checked internally.
+                SSLCredentials sslCredentials = namedGroup.decodeCredentials(
+                        cke.encodedPoint, shc.algorithmConstraints,
+                        s -> shc.conContext.fatal(Alert.INSUFFICIENT_SECURITY,
+                        "ClientKeyExchange " + ng + ": " + s));
 
-                KeyFactory kf = KeyFactory.getInstance("EC");
-                ECPublicKey peerPublicKey =
-                        (ECPublicKey)kf.generatePublic(spec);
-
-                // check constraints of peer ECPublicKey
-                if (!shc.algorithmConstraints.permits(
-                        EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
-                        peerPublicKey)) {
-                    throw new SSLHandshakeException(
-                        "ECPublicKey does not comply to algorithm constraints");
-                }
-
-                shc.handshakeCredentials.add(new ECDHECredentials(
-                        peerPublicKey, namedGroup));
-            } catch (GeneralSecurityException | java.io.IOException e) {
-                throw (SSLHandshakeException)(new SSLHandshakeException(
-                        "Could not generate ECPublicKey").initCause(e));
+                shc.handshakeCredentials.add(sslCredentials);
+            } catch (GeneralSecurityException e) {
+                throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
+                        "Cannot decode named group: " + namedGroup);
             }
 
             // update the states
--- a/src/java.base/share/classes/sun/security/ssl/ECDHKeyExchange.java	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/java.base/share/classes/sun/security/ssl/ECDHKeyExchange.java	Thu Jun 13 11:31:36 2019 +0530
@@ -36,7 +36,6 @@
 import java.security.PublicKey;
 import java.security.SecureRandom;
 import java.security.interfaces.ECPublicKey;
-import java.security.spec.AlgorithmParameterSpec;
 import java.security.spec.ECGenParameterSpec;
 import java.security.spec.ECParameterSpec;
 import java.security.spec.ECPoint;
@@ -44,25 +43,30 @@
 import java.util.EnumSet;
 import javax.crypto.KeyAgreement;
 import javax.crypto.SecretKey;
-import javax.crypto.spec.SecretKeySpec;
 import javax.net.ssl.SSLHandshakeException;
-import sun.security.ssl.CipherSuite.HashAlg;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroupType;
+import sun.security.ssl.NamedGroup.NamedGroupType;
 import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
 import sun.security.ssl.X509Authentication.X509Credentials;
 import sun.security.ssl.X509Authentication.X509Possession;
+import sun.security.ssl.XDHKeyExchange.XDHECredentials;
+import sun.security.ssl.XDHKeyExchange.XDHEPossession;
 import sun.security.util.ECUtil;
 
 final class ECDHKeyExchange {
     static final SSLPossessionGenerator poGenerator =
             new ECDHEPossessionGenerator();
-    static final SSLKeyAgreementGenerator ecdheKAGenerator =
-            new ECDHEKAGenerator();
     static final SSLKeyAgreementGenerator ecdhKAGenerator =
             new ECDHKAGenerator();
 
-    static final class ECDHECredentials implements SSLCredentials {
+    // TLSv1.3
+    static final SSLKeyAgreementGenerator ecdheKAGenerator =
+            new ECDHEKAGenerator();
+
+    // TLSv1-1.2, the KA gets more difficult with EC/XEC keys
+    static final SSLKeyAgreementGenerator ecdheXdhKAGenerator =
+            new ECDHEXDHKAGenerator();
+
+    static final class ECDHECredentials implements NamedGroupCredentials {
         final ECPublicKey popPublicKey;
         final NamedGroup namedGroup;
 
@@ -71,6 +75,16 @@
             this.namedGroup = namedGroup;
         }
 
+        @Override
+        public PublicKey getPublicKey() {
+            return popPublicKey;
+        }
+
+        @Override
+        public NamedGroup getNamedGroup() {
+            return namedGroup;
+        }
+
         static ECDHECredentials valueOf(NamedGroup namedGroup,
             byte[] encodedPoint) throws IOException, GeneralSecurityException {
 
@@ -98,7 +112,7 @@
         }
     }
 
-    static final class ECDHEPossession implements SSLPossession {
+    static final class ECDHEPossession implements NamedGroupPossession {
         final PrivateKey privateKey;
         final ECPublicKey publicKey;
         final NamedGroup namedGroup;
@@ -199,6 +213,21 @@
                         "Could not generate ECPublicKey").initCause(e);
             }
         }
+
+        @Override
+        public PublicKey getPublicKey() {
+            return publicKey;
+        }
+
+        @Override
+        public NamedGroup getNamedGroup() {
+            return namedGroup;
+        }
+
+        @Override
+        public PrivateKey getPrivateKey() {
+            return privateKey;
+        }
     }
 
     private static final
@@ -210,24 +239,31 @@
 
         @Override
         public SSLPossession createPossession(HandshakeContext context) {
-            NamedGroup preferableNamedGroup = null;
+
+            NamedGroup preferableNamedGroup;
+
+            // Find most preferred EC or XEC groups
             if ((context.clientRequestedNamedGroups != null) &&
                     (!context.clientRequestedNamedGroups.isEmpty())) {
                 preferableNamedGroup = SupportedGroups.getPreferredGroup(
                         context.negotiatedProtocol,
                         context.algorithmConstraints,
-                        NamedGroupType.NAMED_GROUP_ECDHE,
+                        new NamedGroupType[] {
+                            NamedGroupType.NAMED_GROUP_ECDHE,
+                            NamedGroupType.NAMED_GROUP_XDH },
                         context.clientRequestedNamedGroups);
             } else {
                 preferableNamedGroup = SupportedGroups.getPreferredGroup(
                         context.negotiatedProtocol,
                         context.algorithmConstraints,
-                        NamedGroupType.NAMED_GROUP_ECDHE);
+                        new NamedGroupType[] {
+                            NamedGroupType.NAMED_GROUP_ECDHE,
+                            NamedGroupType.NAMED_GROUP_XDH });
             }
 
             if (preferableNamedGroup != null) {
-                return new ECDHEPossession(preferableNamedGroup,
-                            context.sslContext.getSecureRandom());
+                return preferableNamedGroup.createPossession(
+                    context.sslContext.getSecureRandom());
             }
 
             // no match found, cannot use this cipher suite.
@@ -298,7 +334,7 @@
                     "No sufficient ECDHE key agreement parameters negotiated");
             }
 
-            return new ECDHEKAKeyDerivation(shc,
+            return new KAKeyDerivation("ECDH", shc,
                 x509Possession.popPrivateKey, ecdheCredentials.popPublicKey);
         }
 
@@ -347,7 +383,7 @@
                     "No sufficient ECDH key agreement parameters negotiated");
             }
 
-            return new ECDHEKAKeyDerivation(chc,
+            return new KAKeyDerivation("ECDH", chc,
                 ecdhePossession.privateKey, x509Credentials.popPublicKey);
         }
     }
@@ -391,94 +427,73 @@
                     "No sufficient ECDHE key agreement parameters negotiated");
             }
 
-            return new ECDHEKAKeyDerivation(context,
+            return new KAKeyDerivation("ECDH", context,
                 ecdhePossession.privateKey, ecdheCredentials.popPublicKey);
         }
     }
 
+    /*
+     * A Generator for TLSv1-1.2 to create a ECDHE or a XDH KeyDerivation
+     * object depending on the negotiated group.
+     */
     private static final
-            class ECDHEKAKeyDerivation implements SSLKeyDerivation {
-        private final HandshakeContext context;
-        private final PrivateKey localPrivateKey;
-        private final PublicKey peerPublicKey;
-
-        ECDHEKAKeyDerivation(HandshakeContext context,
-                PrivateKey localPrivateKey,
-                PublicKey peerPublicKey) {
-            this.context = context;
-            this.localPrivateKey = localPrivateKey;
-            this.peerPublicKey = peerPublicKey;
+            class ECDHEXDHKAGenerator implements SSLKeyAgreementGenerator {
+        // Prevent instantiation of this class.
+        private ECDHEXDHKAGenerator() {
+            // blank
         }
 
         @Override
-        public SecretKey deriveKey(String algorithm,
-                AlgorithmParameterSpec params) throws IOException {
-            if (!context.negotiatedProtocol.useTLS13PlusSpec()) {
-                return t12DeriveKey(algorithm, params);
-            } else {
-                return t13DeriveKey(algorithm, params);
+        public SSLKeyDerivation createKeyDerivation(
+                HandshakeContext context) throws IOException {
+
+            NamedGroupPossession namedGroupPossession = null;
+            NamedGroupCredentials namedGroupCredentials = null;
+            NamedGroup namedGroup = null;
+
+            // Find a possession/credential combo using the same named group
+            search:
+            for (SSLPossession poss : context.handshakePossessions) {
+                for (SSLCredentials cred : context.handshakeCredentials) {
+                    if (((poss instanceof ECDHEPossession) &&
+                            (cred instanceof ECDHECredentials)) ||
+                            (((poss instanceof XDHEPossession) &&
+                            (cred instanceof XDHECredentials)))) {
+                        NamedGroupPossession p = (NamedGroupPossession)poss;
+                        NamedGroupCredentials c = (NamedGroupCredentials)cred;
+                        if (p.getNamedGroup() != c.getNamedGroup()) {
+                            continue;
+                        } else {
+                            namedGroup = p.getNamedGroup();
+                        }
+                        namedGroupPossession = p;
+                        namedGroupCredentials = c;
+                        break search;
+                    }
+                }
             }
-        }
 
-        private SecretKey t12DeriveKey(String algorithm,
-                AlgorithmParameterSpec params) throws IOException {
-            try {
-                KeyAgreement ka = KeyAgreement.getInstance("ECDH");
-                ka.init(localPrivateKey);
-                ka.doPhase(peerPublicKey, true);
-                SecretKey preMasterSecret =
-                        ka.generateSecret("TlsPremasterSecret");
+            if (namedGroupPossession == null || namedGroupCredentials == null) {
+                throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
+                    "No sufficient ECDHE/XDH key agreement " +
+                            "parameters negotiated");
+            }
 
-                SSLMasterKeyDerivation mskd =
-                        SSLMasterKeyDerivation.valueOf(
-                                context.negotiatedProtocol);
-                if (mskd == null) {
-                    // unlikely
-                    throw new SSLHandshakeException(
-                            "No expected master key derivation for protocol: " +
-                            context.negotiatedProtocol.name);
-                }
-                SSLKeyDerivation kd = mskd.createKeyDerivation(
-                        context, preMasterSecret);
-                return kd.deriveKey("MasterSecret", params);
-            } catch (GeneralSecurityException gse) {
-                throw (SSLHandshakeException) new SSLHandshakeException(
-                    "Could not generate secret").initCause(gse);
+            String alg;
+            switch (namedGroup.type) {
+                case NAMED_GROUP_ECDHE:
+                    alg = "ECDH";
+                    break;
+                case NAMED_GROUP_XDH:
+                    alg = "XDH";
+                    break;
+                default:
+                    throw new RuntimeException("Unexpected named group type");
             }
-        }
 
-        private SecretKey t13DeriveKey(String algorithm,
-                AlgorithmParameterSpec params) throws IOException {
-            try {
-                KeyAgreement ka = KeyAgreement.getInstance("ECDH");
-                ka.init(localPrivateKey);
-                ka.doPhase(peerPublicKey, true);
-                SecretKey sharedSecret =
-                        ka.generateSecret("TlsPremasterSecret");
-
-                HashAlg hashAlg = context.negotiatedCipherSuite.hashAlg;
-                SSLKeyDerivation kd = context.handshakeKeyDerivation;
-                HKDF hkdf = new HKDF(hashAlg.name);
-                if (kd == null) {   // No PSK is in use.
-                    // If PSK is not in use Early Secret will still be
-                    // HKDF-Extract(0, 0).
-                    byte[] zeros = new byte[hashAlg.hashLength];
-                    SecretKeySpec ikm =
-                            new SecretKeySpec(zeros, "TlsPreSharedSecret");
-                    SecretKey earlySecret =
-                            hkdf.extract(zeros, ikm, "TlsEarlySecret");
-                    kd = new SSLSecretDerivation(context, earlySecret);
-                }
-
-                // derive salt secret
-                SecretKey saltSecret = kd.deriveKey("TlsSaltSecret", null);
-
-                // derive handshake secret
-                return hkdf.extract(saltSecret, sharedSecret, algorithm);
-            } catch (GeneralSecurityException gse) {
-                throw (SSLHandshakeException) new SSLHandshakeException(
-                    "Could not generate secret").initCause(gse);
-            }
+            return new KAKeyDerivation(alg, context,
+                    namedGroupPossession.getPrivateKey(),
+                    namedGroupCredentials.getPublicKey());
         }
     }
 }
--- a/src/java.base/share/classes/sun/security/ssl/ECDHServerKeyExchange.java	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/java.base/share/classes/sun/security/ssl/ECDHServerKeyExchange.java	Thu Jun 13 11:31:36 2019 +0530
@@ -27,32 +27,21 @@
 
 import java.io.IOException;
 import java.nio.ByteBuffer;
-import java.security.CryptoPrimitive;
+import java.security.GeneralSecurityException;
 import java.security.InvalidAlgorithmParameterException;
 import java.security.InvalidKeyException;
 import java.security.Key;
-import java.security.KeyFactory;
 import java.security.NoSuchAlgorithmException;
 import java.security.PrivateKey;
 import java.security.PublicKey;
 import java.security.Signature;
 import java.security.SignatureException;
-import java.security.interfaces.ECPublicKey;
-import java.security.spec.ECParameterSpec;
-import java.security.spec.ECPoint;
-import java.security.spec.ECPublicKeySpec;
-import java.security.spec.InvalidKeySpecException;
 import java.text.MessageFormat;
-import java.util.EnumSet;
 import java.util.Locale;
-import sun.security.ssl.ECDHKeyExchange.ECDHECredentials;
-import sun.security.ssl.ECDHKeyExchange.ECDHEPossession;
 import sun.security.ssl.SSLHandshake.HandshakeMessage;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
 import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
 import sun.security.ssl.X509Authentication.X509Credentials;
 import sun.security.ssl.X509Authentication.X509Possession;
-import sun.security.util.ECUtil;
 import sun.security.util.HexDumpEncoder;
 
 /**
@@ -80,14 +69,14 @@
         // signature bytes, or null if anonymous
         private final byte[] paramsSignature;
 
-        // public key object encapsulated in this message
-        private final ECPublicKey publicKey;
-
         private final boolean useExplicitSigAlgorithm;
 
         // the signature algorithm used by this ServerKeyExchange message
         private final SignatureScheme signatureScheme;
 
+        // the parsed credential object
+        private SSLCredentials sslCredentials;
+
         ECDHServerKeyExchangeMessage(
                 HandshakeContext handshakeContext) throws IOException {
             super(handshakeContext);
@@ -96,38 +85,38 @@
             ServerHandshakeContext shc =
                     (ServerHandshakeContext)handshakeContext;
 
-            ECDHEPossession ecdhePossession = null;
+            // Find the Possessions needed
+            NamedGroupPossession namedGroupPossession = null;
             X509Possession x509Possession = null;
             for (SSLPossession possession : shc.handshakePossessions) {
-                if (possession instanceof ECDHEPossession) {
-                    ecdhePossession = (ECDHEPossession)possession;
+                if (possession instanceof NamedGroupPossession) {
+                    namedGroupPossession = (NamedGroupPossession)possession;
                     if (x509Possession != null) {
                         break;
                     }
                 } else if (possession instanceof X509Possession) {
                     x509Possession = (X509Possession)possession;
-                    if (ecdhePossession != null) {
+                    if (namedGroupPossession != null) {
                         break;
                     }
                 }
             }
 
-            if (ecdhePossession == null) {
+            if (namedGroupPossession == null) {
                 // unlikely
                 throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
                     "No ECDHE credentials negotiated for server key exchange");
             }
 
-            publicKey = ecdhePossession.publicKey;
-            ECParameterSpec params = publicKey.getParams();
-            ECPoint point = publicKey.getW();
-            publicPoint = ECUtil.encodePoint(point, params.getCurve());
+            // Find the NamedGroup used for the ephemeral keys.
+            namedGroup = namedGroupPossession.getNamedGroup();
+            publicPoint = namedGroup.encodePossessionPublicKey(
+                    namedGroupPossession);
 
-            this.namedGroup = NamedGroup.valueOf(params);
             if ((namedGroup == null) || (namedGroup.oid == null) ) {
                 // unlikely
                 throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
-                    "Unnamed EC parameter spec: " + params);
+                    "Missing Named Group");
             }
 
             if (x509Possession == null) {
@@ -216,39 +205,23 @@
                     "Unsupported named group: " + namedGroup);
             }
 
-            if (namedGroup.oid == null) {
-                throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
-                    "Unknown named EC curve: " + namedGroup);
-            }
-
-            ECParameterSpec parameters =
-                    ECUtil.getECParameterSpec(null, namedGroup.oid);
-            if (parameters == null) {
-                throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
-                    "No supported EC parameter: " + namedGroup);
-            }
-
             publicPoint = Record.getBytes8(m);
             if (publicPoint.length == 0) {
                 throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
-                    "Insufficient ECPoint data: " + namedGroup);
+                    "Insufficient Point data: " + namedGroup);
             }
 
-            ECPublicKey ecPublicKey = null;
             try {
-                ECPoint point =
-                        ECUtil.decodePoint(publicPoint, parameters.getCurve());
-                KeyFactory factory = KeyFactory.getInstance("EC");
-                ecPublicKey = (ECPublicKey)factory.generatePublic(
-                    new ECPublicKeySpec(point, parameters));
-            } catch (NoSuchAlgorithmException |
-                    InvalidKeySpecException | IOException ex) {
-                throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
-                    "Invalid ECPoint: " + namedGroup, ex);
+                sslCredentials = namedGroup.decodeCredentials(
+                    publicPoint, handshakeContext.algorithmConstraints,
+                     s -> chc.conContext.fatal(Alert.INSUFFICIENT_SECURITY,
+                     "ServerKeyExchange " + namedGroup + ": " + (s)));
+            } catch (GeneralSecurityException ex) {
+                throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
+                        "Cannot decode named group: " +
+                        NamedGroup.nameOf(namedGroupId));
             }
 
-            publicKey = ecPublicKey;
-
             X509Credentials x509Credentials = null;
             for (SSLCredentials cd : chc.handshakeCredentials) {
                 if (cd instanceof X509Credentials) {
@@ -529,6 +502,7 @@
             // The consuming happens in client side only.
             ClientHandshakeContext chc = (ClientHandshakeContext)context;
 
+            // AlgorithmConstraints are checked during decoding
             ECDHServerKeyExchangeMessage skem =
                     new ECDHServerKeyExchangeMessage(chc, message);
             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
@@ -537,22 +511,9 @@
             }
 
             //
-            // validate
-            //
-            // check constraints of EC PublicKey
-            if (!chc.algorithmConstraints.permits(
-                    EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
-                    skem.publicKey)) {
-                throw chc.conContext.fatal(Alert.INSUFFICIENT_SECURITY,
-                        "ECDH ServerKeyExchange does not comply " +
-                        "to algorithm constraints");
-            }
-
-            //
             // update
             //
-            chc.handshakeCredentials.add(
-                    new ECDHECredentials(skem.publicKey, skem.namedGroup));
+            chc.handshakeCredentials.add(skem.sslCredentials);
 
             //
             // produce
--- a/src/java.base/share/classes/sun/security/ssl/ECPointFormatsExtension.java	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/java.base/share/classes/sun/security/ssl/ECPointFormatsExtension.java	Thu Jun 13 11:31:36 2019 +0530
@@ -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
@@ -34,7 +34,7 @@
 import sun.security.ssl.SSLExtension.ExtensionConsumer;
 import sun.security.ssl.SSLExtension.SSLExtensionSpec;
 import sun.security.ssl.SSLHandshake.HandshakeMessage;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroupType;
+import sun.security.ssl.NamedGroup.NamedGroupType;
 
 /**
  * Pack of the "ec_point_formats" extensions [RFC 4492].
--- a/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java	Thu Jun 13 11:31:36 2019 +0530
@@ -46,9 +46,8 @@
 import javax.net.ssl.SNIServerName;
 import javax.net.ssl.SSLHandshakeException;
 import javax.security.auth.x500.X500Principal;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroupType;
-import static sun.security.ssl.SupportedGroupsExtension.NamedGroupType.*;
+import sun.security.ssl.NamedGroup.NamedGroupType;
+import static sun.security.ssl.NamedGroup.NamedGroupType.*;
 import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
 
 abstract class HandshakeContext implements ConnectionContext {
@@ -519,31 +518,38 @@
                 return true;
             }
 
-            boolean available;
-            NamedGroupType groupType = suite.keyExchange.groupType;
-            if (groupType != NAMED_GROUP_NONE) {
-                Boolean checkedStatus = cachedStatus.get(groupType);
-                if (checkedStatus == null) {
-                    available = SupportedGroups.isActivatable(
-                            algorithmConstraints, groupType);
-                    cachedStatus.put(groupType, available);
+            // Is at least one of the group types available?
+            boolean groupAvailable, retval = false;
+            NamedGroupType[] groupTypes = suite.keyExchange.groupTypes;
+            for (NamedGroupType groupType : groupTypes) {
+                if (groupType != NAMED_GROUP_NONE) {
+                    Boolean checkedStatus = cachedStatus.get(groupType);
+                    if (checkedStatus == null) {
+                        groupAvailable = SupportedGroups.isActivatable(
+                                algorithmConstraints, groupType);
+                        cachedStatus.put(groupType, groupAvailable);
 
-                    if (!available &&
-                            SSLLogger.isOn && SSLLogger.isOn("verbose")) {
-                        SSLLogger.fine("No activated named group");
+                        if (!groupAvailable &&
+                                SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+                            SSLLogger.fine(
+                                    "No activated named group in " + groupType);
+                        }
+                    } else {
+                        groupAvailable = checkedStatus;
                     }
+
+                    retval |= groupAvailable;
                 } else {
-                    available = checkedStatus;
+                    retval |= true;
                 }
+            }
 
-                if (!available && SSLLogger.isOn && SSLLogger.isOn("verbose")) {
-                    SSLLogger.fine(
-                        "No active named group, ignore " + suite);
-                }
-                return available;
-            } else {
-                return true;
+            if (!retval && SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+                SSLLogger.fine("No active named group(s), ignore " + suite);
             }
+
+            return retval;
+
         } else if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
             SSLLogger.fine("Ignore disabled cipher suite: " + suite);
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java	Thu Jun 13 11:31:36 2019 +0530
@@ -0,0 +1,132 @@
+/*
+ * 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 sun.security.ssl;
+
+import javax.crypto.KeyAgreement;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import javax.net.ssl.SSLHandshakeException;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * A common class for creating various KeyDerivation types.
+ */
+public class KAKeyDerivation implements SSLKeyDerivation {
+
+    private final String algorithmName;
+    private final HandshakeContext context;
+    private final PrivateKey localPrivateKey;
+    private final PublicKey peerPublicKey;
+
+    KAKeyDerivation(String algorithmName,
+            HandshakeContext context,
+            PrivateKey localPrivateKey,
+            PublicKey peerPublicKey) {
+        this.algorithmName = algorithmName;
+        this.context = context;
+        this.localPrivateKey = localPrivateKey;
+        this.peerPublicKey = peerPublicKey;
+    }
+
+    @Override
+    public SecretKey deriveKey(String algorithm,
+            AlgorithmParameterSpec params) throws IOException {
+        if (!context.negotiatedProtocol.useTLS13PlusSpec()) {
+            return t12DeriveKey(algorithm, params);
+        } else {
+            return t13DeriveKey(algorithm, params);
+        }
+    }
+
+    /**
+     * Handle the TLSv1-1.2 objects, which don't use the HKDF algorithms.
+     */
+    private SecretKey t12DeriveKey(String algorithm,
+            AlgorithmParameterSpec params) throws IOException {
+        try {
+            KeyAgreement ka = KeyAgreement.getInstance(algorithmName);
+            ka.init(localPrivateKey);
+            ka.doPhase(peerPublicKey, true);
+            SecretKey preMasterSecret
+                    = ka.generateSecret("TlsPremasterSecret");
+            SSLMasterKeyDerivation mskd
+                    = SSLMasterKeyDerivation.valueOf(
+                            context.negotiatedProtocol);
+            if (mskd == null) {
+                // unlikely
+                throw new SSLHandshakeException(
+                        "No expected master key derivation for protocol: "
+                        + context.negotiatedProtocol.name);
+            }
+            SSLKeyDerivation kd = mskd.createKeyDerivation(
+                    context, preMasterSecret);
+            return kd.deriveKey("MasterSecret", params);
+        } catch (GeneralSecurityException gse) {
+            throw (SSLHandshakeException) new SSLHandshakeException(
+                    "Could not generate secret").initCause(gse);
+        }
+    }
+
+    /**
+     * Handle the TLSv1.3 objects, which use the HKDF algorithms.
+     */
+    private SecretKey t13DeriveKey(String algorithm,
+            AlgorithmParameterSpec params) throws IOException {
+        try {
+            KeyAgreement ka = KeyAgreement.getInstance(algorithmName);
+            ka.init(localPrivateKey);
+            ka.doPhase(peerPublicKey, true);
+            SecretKey sharedSecret
+                    = ka.generateSecret("TlsPremasterSecret");
+
+            CipherSuite.HashAlg hashAlg = context.negotiatedCipherSuite.hashAlg;
+            SSLKeyDerivation kd = context.handshakeKeyDerivation;
+            HKDF hkdf = new HKDF(hashAlg.name);
+            if (kd == null) {   // No PSK is in use.
+                // If PSK is not in use Early Secret will still be
+                // HKDF-Extract(0, 0).
+                byte[] zeros = new byte[hashAlg.hashLength];
+                SecretKeySpec ikm
+                        = new SecretKeySpec(zeros, "TlsPreSharedSecret");
+                SecretKey earlySecret
+                        = hkdf.extract(zeros, ikm, "TlsEarlySecret");
+                kd = new SSLSecretDerivation(context, earlySecret);
+            }
+
+            // derive salt secret
+            SecretKey saltSecret = kd.deriveKey("TlsSaltSecret", null);
+
+            // derive handshake secret
+            return hkdf.extract(saltSecret, sharedSecret, algorithm);
+        } catch (GeneralSecurityException gse) {
+            throw (SSLHandshakeException) new SSLHandshakeException(
+                    "Could not generate secret").initCause(gse);
+        }
+    }
+}
--- a/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java	Thu Jun 13 11:31:36 2019 +0530
@@ -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
@@ -27,27 +27,19 @@
 
 import java.io.IOException;
 import java.nio.ByteBuffer;
-import java.security.CryptoPrimitive;
 import java.security.GeneralSecurityException;
 import java.text.MessageFormat;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.EnumSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import javax.net.ssl.SSLProtocolException;
-import sun.security.ssl.DHKeyExchange.DHECredentials;
-import sun.security.ssl.DHKeyExchange.DHEPossession;
-import sun.security.ssl.ECDHKeyExchange.ECDHECredentials;
-import sun.security.ssl.ECDHKeyExchange.ECDHEPossession;
 import sun.security.ssl.KeyShareExtension.CHKeyShareSpec;
 import sun.security.ssl.SSLExtension.ExtensionConsumer;
 import sun.security.ssl.SSLExtension.SSLExtensionSpec;
 import sun.security.ssl.SSLHandshake.HandshakeMessage;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroupType;
 import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
 import sun.security.util.HexDumpEncoder;
 
@@ -264,8 +256,7 @@
                 for (SSLPossession pos : poses) {
                     // update the context
                     chc.handshakePossessions.add(pos);
-                    if (!(pos instanceof ECDHEPossession) &&
-                            !(pos instanceof DHEPossession)) {
+                    if (!(pos instanceof NamedGroupPossession)) {
                         // May need more possesion types in the future.
                         continue;
                     }
@@ -353,46 +344,18 @@
                     continue;
                 }
 
-                if (ng.type == NamedGroupType.NAMED_GROUP_ECDHE) {
-                    try {
-                        ECDHECredentials ecdhec =
-                            ECDHECredentials.valueOf(ng, entry.keyExchange);
-                        if (ecdhec != null) {
-                            if (!shc.algorithmConstraints.permits(
-                                    EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
-                                    ecdhec.popPublicKey)) {
-                                SSLLogger.warning(
-                                        "ECDHE key share entry does not " +
-                                        "comply to algorithm constraints");
-                            } else {
-                                credentials.add(ecdhec);
-                            }
-                        }
-                    } catch (IOException | GeneralSecurityException ex) {
-                        SSLLogger.warning(
-                                "Cannot decode named group: " +
-                                NamedGroup.nameOf(entry.namedGroupId));
+                try {
+                    SSLCredentials kaCred =
+                        ng.decodeCredentials(entry.keyExchange,
+                        shc.algorithmConstraints,
+                        s -> SSLLogger.warning(s));
+                    if (kaCred != null) {
+                        credentials.add(kaCred);
                     }
-                } else if (ng.type == NamedGroupType.NAMED_GROUP_FFDHE) {
-                    try {
-                        DHECredentials dhec =
-                                DHECredentials.valueOf(ng, entry.keyExchange);
-                        if (dhec != null) {
-                            if (!shc.algorithmConstraints.permits(
-                                    EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
-                                    dhec.popPublicKey)) {
-                                SSLLogger.warning(
-                                        "DHE key share entry does not " +
-                                        "comply to algorithm constraints");
-                            } else {
-                                credentials.add(dhec);
-                            }
-                        }
-                    } catch (IOException | GeneralSecurityException ex) {
-                        SSLLogger.warning(
-                                "Cannot decode named group: " +
-                                NamedGroup.nameOf(entry.namedGroupId));
-                    }
+                } catch (GeneralSecurityException ex) {
+                    SSLLogger.warning(
+                        "Cannot decode named group: " +
+                        NamedGroup.nameOf(entry.namedGroupId));
                 }
             }
 
@@ -526,10 +489,9 @@
             KeyShareEntry keyShare = null;
             for (SSLCredentials cd : shc.handshakeCredentials) {
                 NamedGroup ng = null;
-                if (cd instanceof ECDHECredentials) {
-                    ng = ((ECDHECredentials)cd).namedGroup;
-                } else if (cd instanceof DHECredentials) {
-                    ng = ((DHECredentials)cd).namedGroup;
+                if (cd instanceof NamedGroupCredentials) {
+                    NamedGroupCredentials creds = (NamedGroupCredentials)cd;
+                    ng = creds.getNamedGroup();
                 }
 
                 if (ng == null) {
@@ -547,8 +509,7 @@
 
                 SSLPossession[] poses = ke.createPossessions(shc);
                 for (SSLPossession pos : poses) {
-                    if (!(pos instanceof ECDHEPossession) &&
-                            !(pos instanceof DHEPossession)) {
+                    if (!(pos instanceof NamedGroupPossession)) {
                         // May need more possesion types in the future.
                         continue;
                     }
@@ -567,7 +528,7 @@
                                 me.getKey(), me.getValue());
                     }
 
-                    // We have got one! Don't forgor to break.
+                    // We have got one! Don't forget to break.
                     break;
                 }
             }
@@ -643,49 +604,16 @@
             }
 
             SSLCredentials credentials = null;
-            if (ng.type == NamedGroupType.NAMED_GROUP_ECDHE) {
-                try {
-                    ECDHECredentials ecdhec =
-                            ECDHECredentials.valueOf(ng, keyShare.keyExchange);
-                    if (ecdhec != null) {
-                        if (!chc.algorithmConstraints.permits(
-                                EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
-                                ecdhec.popPublicKey)) {
-                            throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
-                                    "ECDHE key share entry does not " +
-                                    "comply to algorithm constraints");
-                        } else {
-                            credentials = ecdhec;
-                        }
-                    }
-                } catch (IOException | GeneralSecurityException ex) {
-                    throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
-                            "Cannot decode named group: " +
-                            NamedGroup.nameOf(keyShare.namedGroupId));
+            try {
+                SSLCredentials kaCred = ng.decodeCredentials(
+                    keyShare.keyExchange, chc.algorithmConstraints,
+                    s -> chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, s));
+                if (kaCred != null) {
+                    credentials = kaCred;
                 }
-            } else if (ng.type == NamedGroupType.NAMED_GROUP_FFDHE) {
-                try {
-                    DHECredentials dhec =
-                            DHECredentials.valueOf(ng, keyShare.keyExchange);
-                    if (dhec != null) {
-                        if (!chc.algorithmConstraints.permits(
-                                EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
-                                dhec.popPublicKey)) {
-                            throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
-                                    "DHE key share entry does not " +
-                                    "comply to algorithm constraints");
-                        } else {
-                            credentials = dhec;
-                        }
-                    }
-                } catch (IOException | GeneralSecurityException ex) {
-                    throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
-                            "Cannot decode named group: " +
-                            NamedGroup.nameOf(keyShare.namedGroupId));
-                }
-            } else {
+            } catch (GeneralSecurityException ex) {
                 throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
-                        "Unsupported named group: " +
+                        "Cannot decode named group: " +
                         NamedGroup.nameOf(keyShare.namedGroupId));
             }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/security/ssl/NamedGroup.java	Thu Jun 13 11:31:36 2019 +0530
@@ -0,0 +1,781 @@
+/*
+ * 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 sun.security.ssl;
+
+import javax.crypto.spec.DHParameterSpec;
+import javax.net.ssl.SSLException;
+import java.io.IOException;
+import java.security.*;
+import java.security.spec.*;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import javax.crypto.*;
+import sun.security.ssl.DHKeyExchange.DHEPossession;
+import sun.security.ssl.ECDHKeyExchange.ECDHEPossession;
+
+import sun.security.util.ECUtil;
+
+/**
+ * An enum containing all known named groups for use in TLS.
+ *
+ * The enum also contains the required properties of each group and the
+ * required functions (e.g. encoding/decoding).
+ */
+enum NamedGroup {
+    // Elliptic Curves (RFC 4492)
+    //
+    // See sun.security.util.CurveDB for the OIDs
+    // NIST K-163
+
+    SECT163_K1(0x0001, "sect163k1", "1.3.132.0.1",
+            NamedGroupType.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12),
+    SECT163_R1(0x0002, "sect163r1", "1.3.132.0.2",
+            NamedGroupType.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12),
+
+    // NIST B-163
+    SECT163_R2(0x0003, "sect163r2", "1.3.132.0.15",
+            NamedGroupType.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12),
+    SECT193_R1(0x0004, "sect193r1", "1.3.132.0.24",
+            NamedGroupType.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12),
+    SECT193_R2(0x0005, "sect193r2", "1.3.132.0.25",
+            NamedGroupType.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12),
+
+    // NIST K-233
+    SECT233_K1(0x0006, "sect233k1", "1.3.132.0.26",
+            NamedGroupType.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12),
+
+    // NIST B-233
+    SECT233_R1(0x0007, "sect233r1", "1.3.132.0.27",
+            NamedGroupType.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12),
+    SECT239_K1(0x0008, "sect239k1", "1.3.132.0.3",
+            NamedGroupType.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12),
+
+    // NIST K-283
+    SECT283_K1(0x0009, "sect283k1", "1.3.132.0.16",
+            NamedGroupType.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12),
+
+    // NIST B-283
+    SECT283_R1(0x000A, "sect283r1", "1.3.132.0.17",
+            NamedGroupType.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12),
+
+    // NIST K-409
+    SECT409_K1(0x000B, "sect409k1", "1.3.132.0.36",
+            NamedGroupType.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12),
+
+    // NIST B-409
+    SECT409_R1(0x000C, "sect409r1", "1.3.132.0.37",
+            NamedGroupType.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12),
+
+    // NIST K-571
+    SECT571_K1(0x000D, "sect571k1", "1.3.132.0.38",
+            NamedGroupType.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12),
+
+    // NIST B-571
+    SECT571_R1(0x000E, "sect571r1", "1.3.132.0.39",
+            NamedGroupType.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12),
+    SECP160_K1(0x000F, "secp160k1", "1.3.132.0.9",
+            NamedGroupType.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12),
+    SECP160_R1(0x0010, "secp160r1", "1.3.132.0.8",
+            NamedGroupType.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12),
+    SECP160_R2(0x0011, "secp160r2", "1.3.132.0.30",
+            NamedGroupType.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12),
+    SECP192_K1(0x0012, "secp192k1", "1.3.132.0.31",
+            NamedGroupType.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12),
+
+    // NIST P-192
+    SECP192_R1(0x0013, "secp192r1", "1.2.840.10045.3.1.1",
+            NamedGroupType.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12),
+    SECP224_K1(0x0014, "secp224k1", "1.3.132.0.32",
+            NamedGroupType.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12),
+
+    // NIST P-224
+    SECP224_R1(0x0015, "secp224r1", "1.3.132.0.33",
+            NamedGroupType.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12),
+    SECP256_K1(0x0016, "secp256k1", "1.3.132.0.10",
+            NamedGroupType.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12),
+
+    // NIST P-256
+    SECP256_R1(0x0017, "secp256r1", "1.2.840.10045.3.1.7",
+            NamedGroupType.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_13),
+
+    // NIST P-384
+    SECP384_R1(0x0018, "secp384r1", "1.3.132.0.34",
+            NamedGroupType.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_13),
+
+    // NIST P-521
+    SECP521_R1(0x0019, "secp521r1", "1.3.132.0.35",
+            NamedGroupType.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_13),
+
+    // x25519 and x448 (RFC 8422/8446)
+    X25519(0x001D, "x25519", "1.3.101.110",
+            NamedGroupType.NAMED_GROUP_XDH,
+            ProtocolVersion.PROTOCOLS_TO_13),
+    X448(0x001E, "x448", "1.3.101.111",
+            NamedGroupType.NAMED_GROUP_XDH,
+            ProtocolVersion.PROTOCOLS_TO_13),
+
+    // Finite Field Diffie-Hellman Ephemeral Parameters (RFC 7919)
+    FFDHE_2048(0x0100, "ffdhe2048", null,
+            NamedGroupType.NAMED_GROUP_FFDHE,
+            ProtocolVersion.PROTOCOLS_TO_13),
+    FFDHE_3072(0x0101, "ffdhe3072", null,
+            NamedGroupType.NAMED_GROUP_FFDHE,
+            ProtocolVersion.PROTOCOLS_TO_13),
+    FFDHE_4096(0x0102, "ffdhe4096", null,
+            NamedGroupType.NAMED_GROUP_FFDHE,
+            ProtocolVersion.PROTOCOLS_TO_13),
+    FFDHE_6144(0x0103, "ffdhe6144", null,
+            NamedGroupType.NAMED_GROUP_FFDHE,
+            ProtocolVersion.PROTOCOLS_TO_13),
+    FFDHE_8192(0x0104, "ffdhe8192", null,
+            NamedGroupType.NAMED_GROUP_FFDHE,
+            ProtocolVersion.PROTOCOLS_TO_13),
+
+    // Elliptic Curves (RFC 4492)
+    //
+    // arbitrary prime and characteristic-2 curves
+    ARBITRARY_PRIME(0xFF01, "arbitrary_explicit_prime_curves", null,
+            NamedGroupType.NAMED_GROUP_ARBITRARY,
+            ProtocolVersion.PROTOCOLS_TO_12),
+    ARBITRARY_CHAR2(0xFF02, "arbitrary_explicit_char2_curves", null,
+            NamedGroupType.NAMED_GROUP_ARBITRARY,
+            ProtocolVersion.PROTOCOLS_TO_12);
+
+    final int id;               // hash + signature
+    final NamedGroupType type;  // group type
+    final String name;          // literal name
+    final String oid;           // object identifier of the named group
+    final String algorithm;     // signature algorithm
+    final ProtocolVersion[] supportedProtocols;
+    private final NamedGroupFunctions functions;    // may be null
+
+    // Constructor used for all NamedGroup types
+    private NamedGroup(int id, String name, String oid,
+            NamedGroupType namedGroupType,
+            ProtocolVersion[] supportedProtocols) {
+        this.id = id;
+        this.name = name;
+        this.oid = oid;
+        this.type = namedGroupType;
+        this.supportedProtocols = supportedProtocols;
+
+        if (this.type == NamedGroupType.NAMED_GROUP_ECDHE) {
+            this.functions = ECDHFunctions.getInstance();
+            this.algorithm = "EC";
+        } else if (this.type == NamedGroupType.NAMED_GROUP_FFDHE) {
+            this.functions = FFDHFunctions.getInstance();
+            this.algorithm = "DiffieHellman";
+        } else if (this.type == NamedGroupType.NAMED_GROUP_XDH) {
+            this.functions = XDHFunctions.getInstance();
+            this.algorithm = "XDH";
+        } else if (this.type == NamedGroupType.NAMED_GROUP_ARBITRARY) {
+            this.functions = null;
+            this.algorithm = "EC";
+        } else {
+            throw new RuntimeException("Unexpected Named Group Type");
+        }
+    }
+
+    private Optional<NamedGroupFunctions> getFunctions() {
+        return Optional.ofNullable(functions);
+    }
+
+    // The next set of methods search & retrieve NamedGroups.
+
+    static NamedGroup valueOf(int id) {
+        for (NamedGroup group : NamedGroup.values()) {
+            if (group.id == id) {
+                return group;
+            }
+        }
+
+        return null;
+    }
+
+    static NamedGroup valueOf(ECParameterSpec params) {
+        String oid = ECUtil.getCurveName(null, params);
+        if ((oid != null) && (!oid.isEmpty())) {
+            for (NamedGroup group : NamedGroup.values()) {
+                if ((group.type == NamedGroupType.NAMED_GROUP_ECDHE)
+                        && oid.equals(group.oid)) {
+                    return group;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    static NamedGroup valueOf(DHParameterSpec params) {
+        for (NamedGroup ng : NamedGroup.values()) {
+            if (ng.type != NamedGroupType.NAMED_GROUP_FFDHE) {
+                continue;
+            }
+
+            DHParameterSpec ngParams = null;
+            // functions is non-null for FFDHE type
+            AlgorithmParameters aps = ng.functions.getParameters(ng);
+            try {
+                ngParams = aps.getParameterSpec(DHParameterSpec.class);
+            } catch (InvalidParameterSpecException ipse) {
+                // should be unlikely
+            }
+
+            if (ngParams == null) {
+                continue;
+            }
+
+            if (ngParams.getP().equals(params.getP())
+                    && ngParams.getG().equals(params.getG())) {
+                return ng;
+            }
+        }
+
+        return null;
+    }
+
+    static NamedGroup nameOf(String name) {
+        for (NamedGroup group : NamedGroup.values()) {
+            if (group.name.equals(name)) {
+                return group;
+            }
+        }
+
+        return null;
+    }
+
+    static String nameOf(int id) {
+        for (NamedGroup group : NamedGroup.values()) {
+            if (group.id == id) {
+                return group.name;
+            }
+        }
+
+        return "UNDEFINED-NAMED-GROUP(" + id + ")";
+    }
+
+    // Are the NamedGroups available for the protocol desired?
+
+    boolean isAvailable(List<ProtocolVersion> protocolVersions) {
+        for (ProtocolVersion pv : supportedProtocols) {
+            if (protocolVersions.contains(pv)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    boolean isAvailable(ProtocolVersion protocolVersion) {
+        for (ProtocolVersion pv : supportedProtocols) {
+            if (protocolVersion == pv) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    // Are the NamedGroups available for the ciphersuites desired?
+
+    boolean isSupported(List<CipherSuite> cipherSuites) {
+        for (CipherSuite cs : cipherSuites) {
+            boolean isMatch = isAvailable(cs.supportedProtocols);
+            if (isMatch && ((cs.keyExchange == null)
+                    || (NamedGroupType.arrayContains(
+                        cs.keyExchange.groupTypes, type)))) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    // lazy loading of parameters
+    AlgorithmParameters getParameters() {
+        Optional<NamedGroupFunctions> ngf = getFunctions();
+        if (ngf.isEmpty()) {
+            return null;
+        }
+        return ngf.get().getParameters(this);
+    }
+
+    // The next set of methods use the NamedGroupFunctions table
+    // to do various operations in a consistent way.
+
+    AlgorithmParameterSpec getParameterSpec() {
+        Optional<NamedGroupFunctions> ngf = getFunctions();
+        if (ngf.isEmpty()) {
+            return null;
+        }
+        return ngf.get().getParameterSpec(this);
+    }
+
+    byte[] encodePossessionPublicKey(
+            NamedGroupPossession namedGroupPossession) {
+
+        Optional<NamedGroupFunctions> ngf = getFunctions();
+        if (ngf.isEmpty()) {
+            return null;
+        }
+        return ngf.get().encodePossessionPublicKey(namedGroupPossession);
+    }
+
+    SSLCredentials decodeCredentials(byte[] encoded,
+            AlgorithmConstraints constraints,
+            ExceptionSupplier onConstraintFail)
+            throws IOException, GeneralSecurityException {
+
+        Optional<NamedGroupFunctions> ngf = getFunctions();
+        if (ngf.isEmpty()) {
+            return null;
+        }
+        return ngf.get().decodeCredentials(this, encoded, constraints,
+                onConstraintFail);
+    }
+
+    SSLPossession createPossession(SecureRandom random) {
+
+        Optional<NamedGroupFunctions> ngf = getFunctions();
+        if (ngf.isEmpty()) {
+            return null;
+        }
+        return ngf.get().createPossession(this, random);
+    }
+
+    SSLKeyDerivation createKeyDerivation(HandshakeContext hc)
+            throws IOException {
+
+        Optional<NamedGroupFunctions> ngf = getFunctions();
+        if (ngf.isEmpty()) {
+            return null;
+        }
+        return ngf.get().createKeyDerivation(hc);
+
+    }
+
+    boolean isAvailableGroup() {
+        Optional<NamedGroupFunctions> ngfOpt = getFunctions();
+        if (ngfOpt.isEmpty()) {
+            return false;
+        }
+        NamedGroupFunctions ngf = ngfOpt.get();
+        return ngf.isAvailable(this);
+    }
+
+    enum NamedGroupType {
+        NAMED_GROUP_ECDHE,      // Elliptic Curve Groups (ECDHE)
+        NAMED_GROUP_FFDHE,      // Finite Field Groups (DHE)
+        NAMED_GROUP_XDH,        // Finite Field Groups (XDH)
+        NAMED_GROUP_ARBITRARY,  // arbitrary prime and curves (ECDHE)
+        NAMED_GROUP_NONE;       // Not predefined named group
+
+        boolean isSupported(List<CipherSuite> cipherSuites) {
+            for (CipherSuite cs : cipherSuites) {
+                if (cs.keyExchange == null ||
+                        arrayContains(cs.keyExchange.groupTypes, this)) {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        static boolean arrayContains(NamedGroupType[] namedGroupTypes,
+                NamedGroupType namedGroupType) {
+            for (NamedGroupType ng : namedGroupTypes) {
+                if (ng == namedGroupType) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    interface ExceptionSupplier {
+        void apply(String s) throws SSLException;
+    }
+
+    /*
+     * A list of functions to do NamedGroup operations in a
+     * algorithm-independent and consistent way.
+     */
+    private static abstract class NamedGroupFunctions {
+
+        // cache to speed up the parameters construction
+        protected static final Map<NamedGroup, AlgorithmParameters>
+                namedGroupParams = new ConcurrentHashMap<>();
+
+        protected void checkConstraints(PublicKey publicKey,
+                AlgorithmConstraints constraints,
+                ExceptionSupplier onConstraintFail)
+                throws SSLException {
+
+            if (!constraints.permits(
+                    EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
+                    publicKey)) {
+
+                onConstraintFail.apply("key share entry does not "
+                        + "comply with algorithm constraints");
+            }
+        }
+
+        public AlgorithmParameters getParameters(NamedGroup ng) {
+
+            AlgorithmParameters result = namedGroupParams.get(ng);
+            if (result == null) {
+                Optional<AlgorithmParameters> paramsOpt = getParametersImpl(ng);
+                if (paramsOpt.isPresent()) {
+                    result = paramsOpt.get();
+                    namedGroupParams.put(ng, result);
+                }
+            }
+
+            return result;
+        }
+
+        public abstract byte[] encodePossessionPublicKey(
+                NamedGroupPossession namedGroupPossession);
+
+        public abstract SSLCredentials decodeCredentials(
+                NamedGroup ng, byte[] encoded,
+                AlgorithmConstraints constraints,
+                ExceptionSupplier onConstraintFail)
+                throws IOException, GeneralSecurityException;
+
+        public abstract SSLPossession createPossession(NamedGroup ng,
+                SecureRandom random);
+
+        public abstract SSLKeyDerivation createKeyDerivation(
+                HandshakeContext hc) throws IOException;
+
+        protected abstract Optional<AlgorithmParameters> getParametersImpl(
+                NamedGroup ng);
+
+        public abstract AlgorithmParameterSpec getParameterSpec(NamedGroup ng);
+
+        public abstract boolean isAvailable(NamedGroup ng);
+    }
+
+    private static class FFDHFunctions extends NamedGroupFunctions {
+
+        // lazy initialization
+        private static class FunctionsHolder {
+            private static final FFDHFunctions instance = new FFDHFunctions();
+        }
+
+        private static FFDHFunctions getInstance() {
+            return FunctionsHolder.instance;
+        }
+
+        @Override
+        public byte[] encodePossessionPublicKey(
+                NamedGroupPossession namedGroupPossession) {
+            return ((DHEPossession)namedGroupPossession).encode();
+        }
+
+        @Override
+        public SSLCredentials decodeCredentials(NamedGroup ng, byte[] encoded,
+                AlgorithmConstraints constraints,
+                ExceptionSupplier onConstraintFail)
+                throws IOException, GeneralSecurityException {
+
+            DHKeyExchange.DHECredentials result
+                    = DHKeyExchange.DHECredentials.valueOf(ng, encoded);
+
+            checkConstraints(result.getPublicKey(), constraints,
+                    onConstraintFail);
+
+            return result;
+        }
+
+        @Override
+        public SSLPossession createPossession(
+                NamedGroup ng, SecureRandom random) {
+            return new DHKeyExchange.DHEPossession(ng, random);
+        }
+
+        @Override
+        public SSLKeyDerivation createKeyDerivation(HandshakeContext hc)
+                throws IOException {
+
+            return DHKeyExchange.kaGenerator.createKeyDerivation(hc);
+        }
+
+        @Override
+        public AlgorithmParameterSpec getParameterSpec(NamedGroup ng) {
+            return getDHParameterSpec(ng);
+        }
+
+        DHParameterSpec getDHParameterSpec(NamedGroup ng) {
+
+            AlgorithmParameters params = getParameters(ng);
+            try {
+                return params.getParameterSpec(DHParameterSpec.class);
+            } catch (InvalidParameterSpecException ipse) {
+                // should be unlikely
+                return getPredefinedDHParameterSpec(ng);
+            }
+        }
+
+        private static DHParameterSpec getFFDHEDHParameterSpec(
+                NamedGroup namedGroup) {
+
+            DHParameterSpec spec = null;
+            switch (namedGroup) {
+                case FFDHE_2048:
+                    spec = PredefinedDHParameterSpecs.ffdheParams.get(2048);
+                    break;
+                case FFDHE_3072:
+                    spec = PredefinedDHParameterSpecs.ffdheParams.get(3072);
+                    break;
+                case FFDHE_4096:
+                    spec = PredefinedDHParameterSpecs.ffdheParams.get(4096);
+                    break;
+                case FFDHE_6144:
+                    spec = PredefinedDHParameterSpecs.ffdheParams.get(6144);
+                    break;
+                case FFDHE_8192:
+                    spec = PredefinedDHParameterSpecs.ffdheParams.get(8192);
+            }
+
+            return spec;
+        }
+
+        private static DHParameterSpec getPredefinedDHParameterSpec(
+                NamedGroup namedGroup) {
+
+            DHParameterSpec spec = null;
+            switch (namedGroup) {
+                case FFDHE_2048:
+                    spec = PredefinedDHParameterSpecs.definedParams.get(2048);
+                    break;
+                case FFDHE_3072:
+                    spec = PredefinedDHParameterSpecs.definedParams.get(3072);
+                    break;
+                case FFDHE_4096:
+                    spec = PredefinedDHParameterSpecs.definedParams.get(4096);
+                    break;
+                case FFDHE_6144:
+                    spec = PredefinedDHParameterSpecs.definedParams.get(6144);
+                    break;
+                case FFDHE_8192:
+                    spec = PredefinedDHParameterSpecs.definedParams.get(8192);
+            }
+
+            return spec;
+        }
+
+        @Override
+        public boolean isAvailable(NamedGroup ng) {
+
+            AlgorithmParameters params = getParameters(ng);
+            return params != null;
+        }
+
+        @Override
+        protected Optional<AlgorithmParameters> getParametersImpl(
+                NamedGroup ng) {
+            try {
+                AlgorithmParameters params
+                        = AlgorithmParameters.getInstance("DiffieHellman");
+                AlgorithmParameterSpec spec
+                        = getFFDHEDHParameterSpec(ng);
+                params.init(spec);
+                return Optional.of(params);
+            } catch (InvalidParameterSpecException
+                    | NoSuchAlgorithmException ex) {
+                return Optional.empty();
+            }
+        }
+
+    }
+
+    private static class ECDHFunctions extends NamedGroupFunctions {
+
+        // lazy initialization
+        private static class FunctionsHolder {
+            private static final ECDHFunctions instance = new ECDHFunctions();
+        }
+
+        private static ECDHFunctions getInstance() {
+            return FunctionsHolder.instance;
+        }
+
+        @Override
+        public byte[] encodePossessionPublicKey(
+                NamedGroupPossession namedGroupPossession) {
+            return ((ECDHEPossession)namedGroupPossession).encode();
+        }
+
+        @Override
+        public SSLCredentials decodeCredentials(NamedGroup ng, byte[] encoded,
+                AlgorithmConstraints constraints,
+                ExceptionSupplier onConstraintFail)
+                throws IOException, GeneralSecurityException {
+
+            ECDHKeyExchange.ECDHECredentials result
+                    = ECDHKeyExchange.ECDHECredentials.valueOf(ng, encoded);
+
+            checkConstraints(result.getPublicKey(), constraints,
+                    onConstraintFail);
+
+            return result;
+        }
+
+        @Override
+        public SSLPossession createPossession(
+                NamedGroup ng, SecureRandom random) {
+            return new ECDHKeyExchange.ECDHEPossession(ng, random);
+        }
+
+        @Override
+        public SSLKeyDerivation createKeyDerivation(HandshakeContext hc)
+                throws IOException {
+
+            return ECDHKeyExchange.ecdheKAGenerator.createKeyDerivation(hc);
+        }
+
+        @Override
+        public AlgorithmParameterSpec getParameterSpec(NamedGroup ng) {
+            return SupportedGroupsExtension.SupportedGroups
+                    .getECGenParamSpec(ng);
+        }
+
+        @Override
+        public boolean isAvailable(NamedGroup ng) {
+
+            AlgorithmParameters params = getParameters(ng);
+            return params != null;
+        }
+
+        @Override
+        protected Optional<AlgorithmParameters> getParametersImpl(
+                NamedGroup ng) {
+            try {
+                AlgorithmParameters params
+                        = AlgorithmParameters.getInstance("EC");
+                AlgorithmParameterSpec spec
+                        = new ECGenParameterSpec(ng.oid);
+                params.init(spec);
+                return Optional.of(params);
+            } catch (InvalidParameterSpecException
+                    | NoSuchAlgorithmException ex) {
+                return Optional.empty();
+            }
+        }
+    }
+
+    private static class XDHFunctions extends NamedGroupFunctions {
+
+        // lazy initialization
+        private static class FunctionsHolder {
+            private static final XDHFunctions instance = new XDHFunctions();
+        }
+
+        private static XDHFunctions getInstance() {
+            return FunctionsHolder.instance;
+        }
+
+        @Override
+        public byte[] encodePossessionPublicKey(NamedGroupPossession poss) {
+            return ((XDHKeyExchange.XDHEPossession)poss).encode();
+        }
+
+        @Override
+        public SSLCredentials decodeCredentials(NamedGroup ng, byte[] encoded,
+                AlgorithmConstraints constraints,
+                ExceptionSupplier onConstraintFail)
+                throws IOException, GeneralSecurityException {
+
+            XDHKeyExchange.XDHECredentials result
+                    = XDHKeyExchange.XDHECredentials.valueOf(ng, encoded);
+
+            checkConstraints(result.getPublicKey(), constraints,
+                    onConstraintFail);
+
+            return result;
+        }
+
+        @Override
+        public SSLPossession createPossession(
+                NamedGroup ng, SecureRandom random) {
+            return new XDHKeyExchange.XDHEPossession(ng, random);
+        }
+
+        @Override
+        public SSLKeyDerivation createKeyDerivation(HandshakeContext hc)
+                throws IOException {
+            return XDHKeyExchange.xdheKAGenerator.createKeyDerivation(hc);
+        }
+
+        @Override
+        public AlgorithmParameterSpec getParameterSpec(NamedGroup ng) {
+            return new NamedParameterSpec(ng.name);
+        }
+
+        @Override
+        public boolean isAvailable(NamedGroup ng) {
+
+            try {
+                KeyAgreement.getInstance(ng.algorithm);
+                return true;
+            } catch (NoSuchAlgorithmException ex) {
+                return false;
+            }
+        }
+
+        @Override
+        protected Optional<AlgorithmParameters> getParametersImpl(
+                NamedGroup ng) {
+            return Optional.empty();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/security/ssl/NamedGroupCredentials.java	Thu Jun 13 11:31:36 2019 +0530
@@ -0,0 +1,36 @@
+/*
+ * 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 sun.security.ssl;
+
+import java.security.PublicKey;
+
+interface NamedGroupCredentials extends SSLCredentials {
+
+    PublicKey getPublicKey();
+
+    NamedGroup getNamedGroup();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/security/ssl/NamedGroupPossession.java	Thu Jun 13 11:31:36 2019 +0530
@@ -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 sun.security.ssl;
+
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+interface NamedGroupPossession extends SSLPossession {
+
+    NamedGroup getNamedGroup();
+
+    PublicKey getPublicKey();
+
+    PrivateKey getPrivateKey();
+}
--- a/src/java.base/share/classes/sun/security/ssl/SSLExtension.java	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/java.base/share/classes/sun/security/ssl/SSLExtension.java	Thu Jun 13 11:31:36 2019 +0530
@@ -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
@@ -484,6 +484,25 @@
     final SSLHandshake handshakeType;
     final String name;
     final ProtocolVersion[] supportedProtocols;
+
+    /*
+     * networkProducer: produces outbound handshake data.
+     *
+     * onLoadConsumer:  parses inbound data.  It may not be appropriate
+     *                  to act until all of the message inputs have
+     *                  been parsed.  (e.g. parsing keyShares and choosing
+     *                  a local value without having seen the SupportedGroups
+     *                  extension.)
+     *
+     * onLoadAbsence:   if a missing message needs special handling
+     *                  during the load phase.
+     *
+     * onTradeConsumer: act on the parsed message once all inbound data has
+     *                  been traded and parsed.
+     *
+     * onTradeAbsence:  if a missing message needs special handling
+     *                  during the trade phase.
+     */
     final HandshakeProducer networkProducer;
     final ExtensionConsumer onLoadConsumer;
     final HandshakeAbsence  onLoadAbsence;
--- a/src/java.base/share/classes/sun/security/ssl/SSLKeyExchange.java	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/java.base/share/classes/sun/security/ssl/SSLKeyExchange.java	Thu Jun 13 11:31:36 2019 +0530
@@ -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
@@ -30,10 +30,6 @@
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
-import sun.security.ssl.DHKeyExchange.DHEPossession;
-import sun.security.ssl.ECDHKeyExchange.ECDHEPossession;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroupType;
 import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
 import sun.security.ssl.X509Authentication.X509Possession;
 
@@ -243,8 +239,7 @@
     static SSLKeyExchange valueOf(NamedGroup namedGroup) {
         SSLKeyAgreement ka = T13KeyAgreement.valueOf(namedGroup);
         if (ka != null) {
-            return new SSLKeyExchange(
-                null, T13KeyAgreement.valueOf(namedGroup));
+            return new SSLKeyExchange(null, ka);
         }
 
         return null;
@@ -337,7 +332,7 @@
         ECDH            ("ecdh",        null,
                                         ECDHKeyExchange.ecdhKAGenerator),
         ECDHE           ("ecdhe",       ECDHKeyExchange.poGenerator,
-                                        ECDHKeyExchange.ecdheKAGenerator);
+                                        ECDHKeyExchange.ecdheXdhKAGenerator);
 
         final String name;
         final SSLPossessionGenerator possessionGenerator;
@@ -570,27 +565,13 @@
 
         @Override
         public SSLPossession createPossession(HandshakeContext hc) {
-            if (namedGroup.type == NamedGroupType.NAMED_GROUP_ECDHE) {
-                return new ECDHEPossession(
-                        namedGroup, hc.sslContext.getSecureRandom());
-            } else if (namedGroup.type == NamedGroupType.NAMED_GROUP_FFDHE) {
-                return new DHEPossession(
-                        namedGroup, hc.sslContext.getSecureRandom());
-            }
-
-            return null;
+            return namedGroup.createPossession(hc.sslContext.getSecureRandom());
         }
 
         @Override
         public SSLKeyDerivation createKeyDerivation(
                 HandshakeContext hc) throws IOException {
-            if (namedGroup.type == NamedGroupType.NAMED_GROUP_ECDHE) {
-                return ECDHKeyExchange.ecdheKAGenerator.createKeyDerivation(hc);
-            } else if (namedGroup.type == NamedGroupType.NAMED_GROUP_FFDHE) {
-                return DHKeyExchange.kaGenerator.createKeyDerivation(hc);
-            }
-
-            return null;
+            return namedGroup.createKeyDerivation(hc);
         }
     }
 }
--- a/src/java.base/share/classes/sun/security/ssl/SSLSocketInputRecord.java	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketInputRecord.java	Thu Jun 13 11:31:36 2019 +0530
@@ -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
@@ -313,7 +313,9 @@
                     handshakeBuffer.put(handshakeFrag);
                     handshakeBuffer.rewind();
                     break;
-                } if (remaining == handshakeMessageLen) {
+                }
+
+                if (remaining == handshakeMessageLen) {
                     if (handshakeHash.isHashable(handshakeType)) {
                         handshakeHash.receive(handshakeFrag);
                     }
--- a/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java	Thu Jun 13 11:31:36 2019 +0530
@@ -26,7 +26,6 @@
 package sun.security.ssl;
 
 import java.security.*;
-import java.security.interfaces.ECPrivateKey;
 import java.security.spec.AlgorithmParameterSpec;
 import java.security.spec.ECParameterSpec;
 import java.security.spec.MGF1ParameterSpec;
@@ -39,8 +38,7 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroupType;
+import sun.security.ssl.NamedGroup.NamedGroupType;
 import sun.security.ssl.X509Authentication.X509Possession;
 import sun.security.util.KeyUtil;
 import sun.security.util.SignatureUtil;
@@ -432,10 +430,10 @@
         }
         for (SignatureScheme ss : schemes) {
             if (ss.isAvailable && (keySize >= ss.minimalKeySize) &&
-                ss.handshakeSupportedProtocols.contains(version) &&
-                keyAlgorithm.equalsIgnoreCase(ss.keyAlgorithm)) {
-                if (ss.namedGroup != null &&
-                    ss.namedGroup.type == NamedGroupType.NAMED_GROUP_ECDHE) {
+                    ss.handshakeSupportedProtocols.contains(version) &&
+                    keyAlgorithm.equalsIgnoreCase(ss.keyAlgorithm)) {
+                if ((ss.namedGroup != null) && (ss.namedGroup.type ==
+                        NamedGroupType.NAMED_GROUP_ECDHE)) {
                     ECParameterSpec params =
                             x509Possession.getECParameterSpec();
                     if (params != null &&
--- a/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java	Thu Jun 13 11:31:36 2019 +0530
@@ -30,29 +30,24 @@
 import java.security.AlgorithmConstraints;
 import java.security.AlgorithmParameters;
 import java.security.CryptoPrimitive;
-import java.security.NoSuchAlgorithmException;
-import java.security.spec.AlgorithmParameterSpec;
 import java.security.spec.ECGenParameterSpec;
-import java.security.spec.ECParameterSpec;
 import java.security.spec.InvalidParameterSpecException;
 import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.EnumSet;
-import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Locale;
-import java.util.Map;
-import javax.crypto.spec.DHParameterSpec;
 import javax.net.ssl.SSLProtocolException;
 import sun.security.action.GetPropertyAction;
+import sun.security.ssl.NamedGroup.NamedGroupType;
 import static sun.security.ssl.SSLExtension.CH_SUPPORTED_GROUPS;
 import static sun.security.ssl.SSLExtension.EE_SUPPORTED_GROUPS;
 import sun.security.ssl.SSLExtension.ExtensionConsumer;
 import sun.security.ssl.SSLExtension.SSLExtensionSpec;
 import sun.security.ssl.SSLHandshake.HandshakeMessage;
-import sun.security.util.ECUtil;
+
 
 /**
  * Pack of the "supported_groups" extensions [RFC 4492/7919].
@@ -158,320 +153,11 @@
         }
     }
 
-    static enum NamedGroupType {
-        NAMED_GROUP_ECDHE     ("EC"),
-        NAMED_GROUP_FFDHE     ("DiffieHellman"),
-        NAMED_GROUP_X25519    ("x25519"),
-        NAMED_GROUP_X448      ("x448"),
-        NAMED_GROUP_ARBITRARY ("EC"),
-        NAMED_GROUP_NONE      ("");
-
-        private final String algorithm;
-
-        private NamedGroupType(String algorithm) {
-            this.algorithm = algorithm;
-        }
-
-        boolean isSupported(List<CipherSuite> cipherSuites) {
-            for (CipherSuite cs : cipherSuites) {
-                if (cs.keyExchange == null ||
-                        cs.keyExchange.groupType == this) {
-                    return true;
-                }
-            }
-
-            return false;
-        }
-    }
-
-    static enum NamedGroup {
-        // Elliptic Curves (RFC 4492)
-        //
-        // See sun.security.util.CurveDB for the OIDs
-        // NIST K-163
-        SECT163_K1  (0x0001, "sect163k1", "1.3.132.0.1",
-                            NamedGroupType.NAMED_GROUP_ECDHE,
-                            ProtocolVersion.PROTOCOLS_TO_12),
-        SECT163_R1  (0x0002, "sect163r1", "1.3.132.0.2",
-                            NamedGroupType.NAMED_GROUP_ECDHE,
-                            ProtocolVersion.PROTOCOLS_TO_12),
-
-        // NIST B-163
-        SECT163_R2  (0x0003, "sect163r2", "1.3.132.0.15",
-                            NamedGroupType.NAMED_GROUP_ECDHE,
-                            ProtocolVersion.PROTOCOLS_TO_12),
-        SECT193_R1  (0x0004, "sect193r1", "1.3.132.0.24",
-                            NamedGroupType.NAMED_GROUP_ECDHE,
-                            ProtocolVersion.PROTOCOLS_TO_12),
-        SECT193_R2  (0x0005, "sect193r2", "1.3.132.0.25",
-                            NamedGroupType.NAMED_GROUP_ECDHE,
-                            ProtocolVersion.PROTOCOLS_TO_12),
-
-        // NIST K-233
-        SECT233_K1  (0x0006, "sect233k1", "1.3.132.0.26",
-                            NamedGroupType.NAMED_GROUP_ECDHE,
-                            ProtocolVersion.PROTOCOLS_TO_12),
-
-        // NIST B-233
-        SECT233_R1  (0x0007, "sect233r1", "1.3.132.0.27",
-                            NamedGroupType.NAMED_GROUP_ECDHE,
-                            ProtocolVersion.PROTOCOLS_TO_12),
-        SECT239_K1  (0x0008, "sect239k1", "1.3.132.0.3",
-                            NamedGroupType.NAMED_GROUP_ECDHE,
-                            ProtocolVersion.PROTOCOLS_TO_12),
-
-        // NIST K-283
-        SECT283_K1  (0x0009, "sect283k1", "1.3.132.0.16",
-                            NamedGroupType.NAMED_GROUP_ECDHE,
-                            ProtocolVersion.PROTOCOLS_TO_12),
-
-        // NIST B-283
-        SECT283_R1  (0x000A, "sect283r1", "1.3.132.0.17",
-                            NamedGroupType.NAMED_GROUP_ECDHE,
-                            ProtocolVersion.PROTOCOLS_TO_12),
-
-        // NIST K-409
-        SECT409_K1  (0x000B, "sect409k1", "1.3.132.0.36",
-                            NamedGroupType.NAMED_GROUP_ECDHE,
-                            ProtocolVersion.PROTOCOLS_TO_12),
-
-        // NIST B-409
-        SECT409_R1  (0x000C, "sect409r1", "1.3.132.0.37",
-                            NamedGroupType.NAMED_GROUP_ECDHE,
-                            ProtocolVersion.PROTOCOLS_TO_12),
-
-        // NIST K-571
-        SECT571_K1  (0x000D, "sect571k1", "1.3.132.0.38",
-                            NamedGroupType.NAMED_GROUP_ECDHE,
-                            ProtocolVersion.PROTOCOLS_TO_12),
-
-        // NIST B-571
-        SECT571_R1  (0x000E, "sect571r1", "1.3.132.0.39",
-                            NamedGroupType.NAMED_GROUP_ECDHE,
-                            ProtocolVersion.PROTOCOLS_TO_12),
-        SECP160_K1  (0x000F, "secp160k1", "1.3.132.0.9",
-                            NamedGroupType.NAMED_GROUP_ECDHE,
-                            ProtocolVersion.PROTOCOLS_TO_12),
-        SECP160_R1  (0x0010, "secp160r1", "1.3.132.0.8",
-                            NamedGroupType.NAMED_GROUP_ECDHE,
-                            ProtocolVersion.PROTOCOLS_TO_12),
-        SECP160_R2  (0x0011, "secp160r2", "1.3.132.0.30",
-                            NamedGroupType.NAMED_GROUP_ECDHE,
-                            ProtocolVersion.PROTOCOLS_TO_12),
-        SECP192_K1  (0x0012, "secp192k1", "1.3.132.0.31",
-                            NamedGroupType.NAMED_GROUP_ECDHE,
-                            ProtocolVersion.PROTOCOLS_TO_12),
-
-        // NIST P-192
-        SECP192_R1  (0x0013, "secp192r1", "1.2.840.10045.3.1.1",
-                            NamedGroupType.NAMED_GROUP_ECDHE,
-                            ProtocolVersion.PROTOCOLS_TO_12),
-        SECP224_K1  (0x0014, "secp224k1", "1.3.132.0.32",
-                            NamedGroupType.NAMED_GROUP_ECDHE,
-                            ProtocolVersion.PROTOCOLS_TO_12),
-        // NIST P-224
-        SECP224_R1  (0x0015, "secp224r1", "1.3.132.0.33",
-                            NamedGroupType.NAMED_GROUP_ECDHE,
-                            ProtocolVersion.PROTOCOLS_TO_12),
-        SECP256_K1  (0x0016, "secp256k1", "1.3.132.0.10",
-                            NamedGroupType.NAMED_GROUP_ECDHE,
-                            ProtocolVersion.PROTOCOLS_TO_12),
-
-        // NIST P-256
-        SECP256_R1  (0x0017, "secp256r1", "1.2.840.10045.3.1.7",
-                            NamedGroupType.NAMED_GROUP_ECDHE,
-                            ProtocolVersion.PROTOCOLS_TO_13),
-
-        // NIST P-384
-        SECP384_R1  (0x0018, "secp384r1", "1.3.132.0.34",
-                            NamedGroupType.NAMED_GROUP_ECDHE,
-                            ProtocolVersion.PROTOCOLS_TO_13),
-
-        // NIST P-521
-        SECP521_R1  (0x0019, "secp521r1", "1.3.132.0.35",
-                            NamedGroupType.NAMED_GROUP_ECDHE,
-                            ProtocolVersion.PROTOCOLS_TO_13),
-
-        // x25519 and x448
-        X25519      (0x001D, "x25519", null,
-                            NamedGroupType.NAMED_GROUP_X25519,
-                            ProtocolVersion.PROTOCOLS_TO_13),
-        X448        (0x001E, "x448", null,
-                            NamedGroupType.NAMED_GROUP_X448,
-                            ProtocolVersion.PROTOCOLS_TO_13),
-
-        // Finite Field Diffie-Hellman Ephemeral Parameters (RFC 7919)
-        FFDHE_2048  (0x0100, "ffdhe2048", null,
-                            NamedGroupType.NAMED_GROUP_FFDHE,
-                            ProtocolVersion.PROTOCOLS_TO_13),
-        FFDHE_3072  (0x0101, "ffdhe3072", null,
-                            NamedGroupType.NAMED_GROUP_FFDHE,
-                            ProtocolVersion.PROTOCOLS_TO_13),
-        FFDHE_4096  (0x0102, "ffdhe4096", null,
-                            NamedGroupType.NAMED_GROUP_FFDHE,
-                            ProtocolVersion.PROTOCOLS_TO_13),
-        FFDHE_6144  (0x0103, "ffdhe6144", null,
-                            NamedGroupType.NAMED_GROUP_FFDHE,
-                            ProtocolVersion.PROTOCOLS_TO_13),
-        FFDHE_8192  (0x0104, "ffdhe8192", null,
-                            NamedGroupType.NAMED_GROUP_FFDHE,
-                            ProtocolVersion.PROTOCOLS_TO_13),
-
-        // Elliptic Curves (RFC 4492)
-        //
-        // arbitrary prime and characteristic-2 curves
-        ARBITRARY_PRIME  (0xFF01, "arbitrary_explicit_prime_curves", null,
-                            NamedGroupType.NAMED_GROUP_ARBITRARY,
-                            ProtocolVersion.PROTOCOLS_TO_12),
-        ARBITRARY_CHAR2  (0xFF02, "arbitrary_explicit_char2_curves", null,
-                            NamedGroupType.NAMED_GROUP_ARBITRARY,
-                            ProtocolVersion.PROTOCOLS_TO_12);
-
-        final int id;               // hash + signature
-        final NamedGroupType type;  // group type
-        final String name;          // literal name
-        final String oid;           // object identifier of the named group
-        final String algorithm;     // signature algorithm
-        final ProtocolVersion[] supportedProtocols;
-
-        private NamedGroup(int id, String name, String oid,
-                NamedGroupType namedGroupType,
-                ProtocolVersion[] supportedProtocols) {
-            this.id = id;
-            this.type = namedGroupType;
-            this.name = name;
-            this.oid = oid;
-            this.algorithm = namedGroupType.algorithm;
-            this.supportedProtocols = supportedProtocols;
-        }
-
-        static NamedGroup valueOf(int id) {
-            for (NamedGroup group : NamedGroup.values()) {
-                if (group.id == id) {
-                    return group;
-                }
-            }
-
-            return null;
-        }
-
-        static NamedGroup valueOf(ECParameterSpec params) {
-            String oid = ECUtil.getCurveName(null, params);
-            if ((oid != null) && (!oid.isEmpty())) {
-                for (NamedGroup group : NamedGroup.values()) {
-                    if ((group.type == NamedGroupType.NAMED_GROUP_ECDHE) &&
-                            oid.equals(group.oid)) {
-                        return group;
-                    }
-                }
-            }
-
-            return null;
-        }
-
-        static NamedGroup valueOf(DHParameterSpec params) {
-            for (Map.Entry<NamedGroup, AlgorithmParameters> me :
-                    SupportedGroups.namedGroupParams.entrySet()) {
-                NamedGroup ng = me.getKey();
-                if (ng.type != NamedGroupType.NAMED_GROUP_FFDHE) {
-                    continue;
-                }
-
-                DHParameterSpec ngParams = null;
-                AlgorithmParameters aps = me.getValue();
-                try {
-                    ngParams = aps.getParameterSpec(DHParameterSpec.class);
-                } catch (InvalidParameterSpecException ipse) {
-                    // should be unlikely
-                }
-
-                if (ngParams == null) {
-                    continue;
-                }
-
-                if (ngParams.getP().equals(params.getP()) &&
-                        ngParams.getG().equals(params.getG())) {
-                    return ng;
-                }
-            }
-
-            return null;
-        }
-
-        static NamedGroup nameOf(String name) {
-            for (NamedGroup group : NamedGroup.values()) {
-                if (group.name.equals(name)) {
-                    return group;
-                }
-            }
-
-            return null;
-        }
-
-        static String nameOf(int id) {
-            for (NamedGroup group : NamedGroup.values()) {
-                if (group.id == id) {
-                    return group.name;
-                }
-            }
-
-            return "UNDEFINED-NAMED-GROUP(" + id + ")";
-        }
-
-        boolean isAvailable(List<ProtocolVersion> protocolVersions) {
-            for (ProtocolVersion pv : supportedProtocols) {
-                if (protocolVersions.contains(pv)) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        boolean isAvailable(ProtocolVersion protocolVersion) {
-            for (ProtocolVersion pv : supportedProtocols) {
-                if (protocolVersion == pv) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        boolean isSupported(List<CipherSuite> cipherSuites) {
-            for (CipherSuite cs : cipherSuites) {
-                boolean isMatch = isAvailable(cs.supportedProtocols);
-                if (isMatch && (cs.keyExchange == null ||
-                        cs.keyExchange.groupType == type)) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        // lazy loading of parameters
-        AlgorithmParameters getParameters() {
-            return SupportedGroups.namedGroupParams.get(this);
-        }
-
-        AlgorithmParameterSpec getParameterSpec() {
-            if (this.type == NamedGroupType.NAMED_GROUP_ECDHE) {
-                return SupportedGroups.getECGenParamSpec(this);
-            } else if (this.type == NamedGroupType.NAMED_GROUP_FFDHE) {
-                return SupportedGroups.getDHParameterSpec(this);
-            }
-
-            return null;
-        }
-    }
-
     static class SupportedGroups {
         // To switch off the supported_groups extension for DHE cipher suite.
         static final boolean enableFFDHE =
                 Utilities.getBooleanProperty("jsse.enableFFDHE", true);
 
-        // cache to speed up the parameters construction
-        static final Map<NamedGroup,
-                    AlgorithmParameters> namedGroupParams = new HashMap<>();
-
         // the supported named groups
         static final NamedGroup[] supportedNamedGroups;
 
@@ -516,10 +202,19 @@
                 }
             } else {        // default groups
                 NamedGroup[] groups = new NamedGroup[] {
-                        // NIST curves first
+
+                        // Primary XDH (RFC 7748) curves
+                        NamedGroup.X25519,
+
+                        // Primary NIST curves (e.g. used in TLSv1.3)
                         NamedGroup.SECP256_R1,
                         NamedGroup.SECP384_R1,
                         NamedGroup.SECP521_R1,
+
+                        // Secondary XDH curves
+                        NamedGroup.X448,
+
+                        // Secondary NIST curves
                         NamedGroup.SECT283_K1,
                         NamedGroup.SECT283_R1,
                         NamedGroup.SECT409_K1,
@@ -530,7 +225,7 @@
                         // non-NIST curves
                         NamedGroup.SECP256_K1,
 
-                        // FFDHE 2048
+                        // FFDHE (RFC 7919)
                         NamedGroup.FFDHE_2048,
                         NamedGroup.FFDHE_3072,
                         NamedGroup.FFDHE_4096,
@@ -560,126 +255,27 @@
 
         // check whether the group is supported by the underlying providers
         private static boolean isAvailableGroup(NamedGroup namedGroup) {
-            AlgorithmParameters params = null;
-            AlgorithmParameterSpec spec = null;
-            if (namedGroup.type == NamedGroupType.NAMED_GROUP_ECDHE) {
-                if (namedGroup.oid != null) {
-                    try {
-                        params = AlgorithmParameters.getInstance("EC");
-                        spec = new ECGenParameterSpec(namedGroup.oid);
-                    } catch (NoSuchAlgorithmException e) {
-                        return false;
-                    }
-                }
-            } else if (namedGroup.type == NamedGroupType.NAMED_GROUP_FFDHE) {
-                try {
-                    params = AlgorithmParameters.getInstance("DiffieHellman");
-                    spec = getFFDHEDHParameterSpec(namedGroup);
-                } catch (NoSuchAlgorithmException e) {
-                    return false;
-                }
-            }   // Otherwise, unsupported.
+            return namedGroup.isAvailableGroup();
+        }
 
-            if ((params != null) && (spec != null)) {
-                try {
-                    params.init(spec);
-                } catch (InvalidParameterSpecException e) {
-                    return false;
-                }
-
-                // cache the parameters
-                namedGroupParams.put(namedGroup, params);
-
-                return true;
+        static ECGenParameterSpec getECGenParamSpec(NamedGroup ng) {
+            if (ng.type != NamedGroupType.NAMED_GROUP_ECDHE) {
+                 throw new RuntimeException(
+                         "Not a named EC group: " + ng);
             }
 
-            return false;
-        }
-
-        private static DHParameterSpec getFFDHEDHParameterSpec(
-                NamedGroup namedGroup) {
-            DHParameterSpec spec = null;
-            switch (namedGroup) {
-                case FFDHE_2048:
-                    spec = PredefinedDHParameterSpecs.ffdheParams.get(2048);
-                    break;
-                case FFDHE_3072:
-                    spec = PredefinedDHParameterSpecs.ffdheParams.get(3072);
-                    break;
-                case FFDHE_4096:
-                    spec = PredefinedDHParameterSpecs.ffdheParams.get(4096);
-                    break;
-                case FFDHE_6144:
-                    spec = PredefinedDHParameterSpecs.ffdheParams.get(6144);
-                    break;
-                case FFDHE_8192:
-                    spec = PredefinedDHParameterSpecs.ffdheParams.get(8192);
-            }
-
-            return spec;
-        }
-
-        private static DHParameterSpec getPredefinedDHParameterSpec(
-                NamedGroup namedGroup) {
-            DHParameterSpec spec = null;
-            switch (namedGroup) {
-                case FFDHE_2048:
-                    spec = PredefinedDHParameterSpecs.definedParams.get(2048);
-                    break;
-                case FFDHE_3072:
-                    spec = PredefinedDHParameterSpecs.definedParams.get(3072);
-                    break;
-                case FFDHE_4096:
-                    spec = PredefinedDHParameterSpecs.definedParams.get(4096);
-                    break;
-                case FFDHE_6144:
-                    spec = PredefinedDHParameterSpecs.definedParams.get(6144);
-                    break;
-                case FFDHE_8192:
-                    spec = PredefinedDHParameterSpecs.definedParams.get(8192);
-            }
-
-            return spec;
-        }
-
-        static ECGenParameterSpec getECGenParamSpec(NamedGroup namedGroup) {
-            if (namedGroup.type != NamedGroupType.NAMED_GROUP_ECDHE) {
-                throw new RuntimeException(
-                        "Not a named EC group: " + namedGroup);
-            }
-
-            AlgorithmParameters params = namedGroupParams.get(namedGroup);
-            if (params == null) {
-                throw new RuntimeException(
-                        "Not a supported EC named group: " + namedGroup);
-            }
-
+            // parameters are non-null
+            AlgorithmParameters params = ng.getParameters();
             try {
                 return params.getParameterSpec(ECGenParameterSpec.class);
             } catch (InvalidParameterSpecException ipse) {
                 // should be unlikely
-                return new ECGenParameterSpec(namedGroup.oid);
+                return new ECGenParameterSpec(ng.oid);
             }
         }
 
-        static DHParameterSpec getDHParameterSpec(NamedGroup namedGroup) {
-            if (namedGroup.type != NamedGroupType.NAMED_GROUP_FFDHE) {
-                throw new RuntimeException(
-                        "Not a named DH group: " + namedGroup);
-            }
-
-            AlgorithmParameters params = namedGroupParams.get(namedGroup);
-            if (params == null) {
-                throw new RuntimeException(
-                        "Not a supported DH named group: " + namedGroup);
-            }
-
-            try {
-                return params.getParameterSpec(DHParameterSpec.class);
-            } catch (InvalidParameterSpecException ipse) {
-                // should be unlikely
-                return getPredefinedDHParameterSpec(namedGroup);
-            }
+        static AlgorithmParameters getParameters(NamedGroup ng) {
+            return ng.getParameters();
         }
 
         // Is there any supported group permitted by the constraints?
@@ -692,7 +288,7 @@
                     if (constraints.permits(
                             EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
                             namedGroup.algorithm,
-                            namedGroupParams.get(namedGroup))) {
+                            getParameters(namedGroup))) {
 
                         return true;
                     }
@@ -723,7 +319,7 @@
             return constraints.permits(
                             EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
                             namedGroup.algorithm,
-                            namedGroupParams.get(namedGroup));
+                            getParameters(namedGroup));
         }
 
         // Is the named group supported?
@@ -739,16 +335,16 @@
 
         static NamedGroup getPreferredGroup(
                 ProtocolVersion negotiatedProtocol,
-                AlgorithmConstraints constraints, NamedGroupType type,
+                AlgorithmConstraints constraints, NamedGroupType[] types,
                 List<NamedGroup> requestedNamedGroups) {
             for (NamedGroup namedGroup : requestedNamedGroups) {
-                if ((namedGroup.type == type) &&
+                if ((NamedGroupType.arrayContains(types, namedGroup.type)) &&
                         namedGroup.isAvailable(negotiatedProtocol) &&
                         isSupported(namedGroup) &&
                         constraints.permits(
                                 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
                                 namedGroup.algorithm,
-                                namedGroupParams.get(namedGroup))) {
+                                getParameters(namedGroup))) {
                     return namedGroup;
                 }
             }
@@ -758,14 +354,14 @@
 
         static NamedGroup getPreferredGroup(
                 ProtocolVersion negotiatedProtocol,
-                AlgorithmConstraints constraints, NamedGroupType type) {
+                AlgorithmConstraints constraints, NamedGroupType[] types) {
             for (NamedGroup namedGroup : supportedNamedGroups) {
-                if ((namedGroup.type == type) &&
+                if ((NamedGroupType.arrayContains(types, namedGroup.type)) &&
                         namedGroup.isAvailable(negotiatedProtocol) &&
                         constraints.permits(
                                 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
                                 namedGroup.algorithm,
-                                namedGroupParams.get(namedGroup))) {
+                                getParameters(namedGroup))) {
                     return namedGroup;
                 }
             }
@@ -813,7 +409,7 @@
                         ng.isSupported(chc.activeCipherSuites) &&
                         chc.algorithmConstraints.permits(
                             EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
-                            ng.algorithm, namedGroupParams.get(ng))) {
+                            ng.algorithm, getParameters(ng))) {
                     namedGroups.add(ng);
                 } else if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
                     SSLLogger.fine(
@@ -940,7 +536,7 @@
                         ng.isSupported(shc.activeCipherSuites) &&
                         shc.algorithmConstraints.permits(
                             EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
-                            ng.algorithm, namedGroupParams.get(ng))) {
+                            ng.algorithm, getParameters(ng))) {
                     namedGroups.add(ng);
                 } else if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
                     SSLLogger.fine(
--- a/src/java.base/share/classes/sun/security/ssl/TransportContext.java	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/java.base/share/classes/sun/security/ssl/TransportContext.java	Thu Jun 13 11:31:36 2019 +0530
@@ -39,7 +39,6 @@
 import javax.net.ssl.SSLEngineResult.HandshakeStatus;
 import javax.net.ssl.SSLException;
 import javax.net.ssl.SSLSocket;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
 
 /**
  * SSL/(D)TLS transportation context.
--- a/src/java.base/share/classes/sun/security/ssl/Utilities.java	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/java.base/share/classes/sun/security/ssl/Utilities.java	Thu Jun 13 11:31:36 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -61,8 +61,8 @@
 
         int size = serverNames.size();
         List<SNIServerName> sniList = (size != 0) ?
-                new ArrayList<SNIServerName>(serverNames) :
-                new ArrayList<SNIServerName>(1);
+                new ArrayList<>(serverNames) :
+                new ArrayList<>(1);
 
         boolean reset = false;
         for (int i = 0; i < size; i++) {
@@ -147,7 +147,7 @@
     static String indent(String source, String prefix) {
         StringBuilder builder = new StringBuilder();
         if (source == null) {
-             builder.append("\n" + prefix + "<blank message>");
+             builder.append("\n").append(prefix).append("<blank message>");
         } else {
             String[] lines = lineBreakPatern.split(source);
             boolean isFirst = true;
@@ -232,4 +232,21 @@
         }
         return b;
     }
+
+    static void reverseBytes(byte[] arr) {
+        int i = 0;
+        int j = arr.length - 1;
+
+        while (i < j) {
+            swap(arr, i, j);
+            i++;
+            j--;
+        }
+    }
+
+    private static void swap(byte[] arr, int i, int j) {
+        byte tmp = arr[i];
+        arr[i] = arr[j];
+        arr[j] = tmp;
+    }
 }
--- a/src/java.base/share/classes/sun/security/ssl/X509Authentication.java	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/java.base/share/classes/sun/security/ssl/X509Authentication.java	Thu Jun 13 11:31:36 2019 +0530
@@ -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
@@ -30,13 +30,15 @@
 import java.security.cert.X509Certificate;
 import java.security.interfaces.ECKey;
 import java.security.interfaces.ECPublicKey;
+import java.security.interfaces.XECKey;
+import java.security.spec.AlgorithmParameterSpec;
 import java.security.spec.ECParameterSpec;
+import java.security.spec.NamedParameterSpec;
 import java.util.AbstractMap.SimpleImmutableEntry;
 import java.util.Map;
 import javax.net.ssl.SSLEngine;
 import javax.net.ssl.SSLSocket;
 import javax.net.ssl.X509ExtendedKeyManager;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
 import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
 
 enum X509Authentication implements SSLAuthentication {
@@ -148,6 +150,35 @@
 
             return null;
         }
+
+        // Similar to above, but for XEC.
+        NamedParameterSpec getXECParameterSpec() {
+            if (popPrivateKey == null ||
+                    !"XEC".equals(popPrivateKey.getAlgorithm())) {
+                return null;
+            }
+
+            if (popPrivateKey instanceof XECKey) {
+                AlgorithmParameterSpec params =
+                        ((XECKey)popPrivateKey).getParams();
+                if (params instanceof NamedParameterSpec){
+                    return (NamedParameterSpec)params;
+                }
+            } else if (popCerts != null && popCerts.length != 0) {
+                // The private key not extractable, get the parameters from
+                // the X.509 certificate.
+                PublicKey publicKey = popCerts[0].getPublicKey();
+                if (publicKey instanceof XECKey) {
+                    AlgorithmParameterSpec params =
+                            ((XECKey)publicKey).getParams();
+                    if (params instanceof NamedParameterSpec){
+                        return (NamedParameterSpec)params;
+                    }
+                }
+            }
+
+            return null;
+        }
     }
 
     static final class X509Credentials implements SSLCredentials {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/security/ssl/XDHKeyExchange.java	Thu Jun 13 11:31:36 2019 +0530
@@ -0,0 +1,210 @@
+/*
+ * 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 sun.security.ssl;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.*;
+import java.security.interfaces.XECPublicKey;
+import java.security.spec.*;
+import sun.security.ssl.NamedGroup.NamedGroupType;
+import sun.security.util.*;
+
+/**
+ * Specifics for XEC/XDH Keys/Exchanges
+ */
+final class XDHKeyExchange {
+
+    static final SSLKeyAgreementGenerator xdheKAGenerator
+            = new XDHEKAGenerator();
+
+    static final class XDHECredentials implements NamedGroupCredentials {
+
+        final XECPublicKey popPublicKey;
+        final NamedGroup namedGroup;
+
+        XDHECredentials(XECPublicKey popPublicKey, NamedGroup namedGroup) {
+            this.popPublicKey = popPublicKey;
+            this.namedGroup = namedGroup;
+        }
+
+        @Override
+        public PublicKey getPublicKey() {
+            return popPublicKey;
+        }
+
+        @Override
+        public NamedGroup getNamedGroup() {
+            return namedGroup;
+        }
+
+        /**
+         * Parse the encoded Point into the XDHECredentials using the
+         * namedGroup.
+         */
+        static XDHECredentials valueOf(NamedGroup namedGroup,
+                byte[] encodedPoint) throws IOException,
+                GeneralSecurityException {
+
+            if (namedGroup.type != NamedGroupType.NAMED_GROUP_XDH) {
+                throw new RuntimeException(
+                        "Credentials decoding:  Not XDH named group");
+            }
+
+            if (encodedPoint == null || encodedPoint.length == 0) {
+                return null;
+            }
+
+            byte[] uBytes = encodedPoint.clone();
+            Utilities.reverseBytes(uBytes);
+            BigInteger u = new BigInteger(1, uBytes);
+
+            XECPublicKeySpec xecPublicKeySpec = new XECPublicKeySpec(
+                    new NamedParameterSpec(namedGroup.name), u);
+            KeyFactory factory = KeyFactory.getInstance(namedGroup.algorithm);
+            XECPublicKey publicKey = (XECPublicKey) factory.generatePublic(
+                    xecPublicKeySpec);
+
+            return new XDHECredentials(publicKey, namedGroup);
+        }
+    }
+
+    static final class XDHEPossession implements NamedGroupPossession {
+
+        final PrivateKey privateKey;
+        final XECPublicKey publicKey;
+        final NamedGroup namedGroup;
+
+        XDHEPossession(NamedGroup namedGroup, SecureRandom random) {
+            try {
+                KeyPairGenerator kpg
+                        = KeyPairGenerator.getInstance(namedGroup.algorithm);
+                AlgorithmParameterSpec params = namedGroup.getParameterSpec();
+                kpg.initialize(params, random);
+                KeyPair kp = kpg.generateKeyPair();
+                privateKey = kp.getPrivate();
+                publicKey = (XECPublicKey) kp.getPublic();
+            } catch (GeneralSecurityException e) {
+                throw new RuntimeException(
+                        "Could not generate XDH keypair", e);
+            }
+
+            this.namedGroup = namedGroup;
+        }
+
+        @Override
+        public byte[] encode() {
+
+            byte[] uBytes = ECUtil.trimZeroes(publicKey.getU().toByteArray());
+
+            int expLength;
+            switch (namedGroup) {
+                case X25519:
+                    expLength = 32;
+                    break;
+                case X448:
+                    expLength = 56;
+                    break;
+                default:
+                    throw new RuntimeException("Invalid XDH group");
+            }
+
+            if (uBytes.length > expLength) {
+                throw new RuntimeException("Encoded XDH key too large");
+            }
+
+            if (uBytes.length != expLength) {
+                byte[] tmp = new byte[expLength];
+                System.arraycopy(uBytes, 0, tmp,
+                        expLength - uBytes.length, uBytes.length);
+                uBytes = tmp;
+            }
+
+            Utilities.reverseBytes(uBytes);
+            return (uBytes);
+        }
+
+        @Override
+        public PublicKey getPublicKey() {
+            return publicKey;
+        }
+
+        @Override
+        public NamedGroup getNamedGroup() {
+            return namedGroup;
+        }
+
+        @Override
+        public PrivateKey getPrivateKey() {
+            return privateKey;
+        }
+    }
+
+    private static final class XDHEKAGenerator
+            implements SSLKeyAgreementGenerator {
+
+        // Prevent instantiation of this class.
+        private XDHEKAGenerator() {
+            // blank
+        }
+
+        @Override
+        public SSLKeyDerivation createKeyDerivation(
+                HandshakeContext context) throws IOException {
+            XDHEPossession xdhePossession = null;
+            XDHECredentials xdheCredentials = null;
+            for (SSLPossession poss : context.handshakePossessions) {
+                if (!(poss instanceof XDHEPossession)) {
+                    continue;
+                }
+
+                NamedGroup ng = ((XDHEPossession) poss).namedGroup;
+                for (SSLCredentials cred : context.handshakeCredentials) {
+                    if (!(cred instanceof XDHECredentials)) {
+                        continue;
+                    }
+                    if (ng.equals(((XDHECredentials) cred).namedGroup)) {
+                        xdheCredentials = (XDHECredentials) cred;
+                        break;
+                    }
+                }
+
+                if (xdheCredentials != null) {
+                    xdhePossession = (XDHEPossession) poss;
+                    break;
+                }
+            }
+
+            if (xdhePossession == null || xdheCredentials == null) {
+                context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
+                        "No sufficient XDHE key agreement "
+                        + "parameters negotiated");
+            }
+
+            return new KAKeyDerivation("XDH", context,
+                    xdhePossession.privateKey, xdheCredentials.popPublicKey);
+        }
+    }
+}
--- a/src/java.security.jgss/share/classes/sun/security/jgss/spnego/NegTokenTarg.java	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/java.security.jgss/share/classes/sun/security/jgss/spnego/NegTokenTarg.java	Thu Jun 13 11:31:36 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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 sun.security.jgss.spnego;
 
 import java.io.*;
-import java.util.*;
 import org.ietf.jgss.*;
 import sun.security.jgss.*;
 import sun.security.util.*;
@@ -113,18 +112,6 @@
                 mic.putOctetString(mechListMIC);
                 targToken.write(DerValue.createTag(DerValue.TAG_CONTEXT,
                                         true, (byte) 0x03), mic);
-            } else if (GSSUtil.useMSInterop()) {
-                // required for MS-interoperability
-                if (responseToken != null) {
-                    if (DEBUG) {
-                        System.out.println("SpNegoToken NegTokenTarg: " +
-                                "sending additional token for MS Interop");
-                    }
-                    DerOutputStream rspToken = new DerOutputStream();
-                    rspToken.putOctetString(responseToken);
-                    targToken.write(DerValue.createTag(DerValue.TAG_CONTEXT,
-                                                true, (byte) 0x03), rspToken);
-                }
             }
 
             // insert in a SEQUENCE
--- a/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java	Thu Jun 13 11:31:36 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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
@@ -66,7 +66,7 @@
     static {
         MECH_MAP =
             AccessController.doPrivileged(
-                new PrivilegedAction<HashMap<String, String>>() {
+                new PrivilegedAction<>() {
                     public HashMap<String, String> run() {
                         DEBUG = Boolean.parseBoolean(
                             System.getProperty("sun.security.nativegss.debug"));
@@ -77,7 +77,7 @@
                             if (DEBUG) err.printStackTrace();
                             return null;
                         }
-                        String[] gssLibs = new String[0];
+                        String[] gssLibs;
                         String defaultLib
                                 = System.getProperty("sun.security.jgss.lib");
                         if (defaultLib == null || defaultLib.trim().equals("")) {
@@ -95,6 +95,12 @@
                                     "libgssapi_krb5.dylib",
                                     "/usr/lib/sasl2/libgssapiv2.2.so",
                                };
+                            } else if (osname.contains("Windows")) {
+                                // Full path needed, DLL is in jre/bin
+                                gssLibs = new String[]{ System.getProperty("java.home")
+                                        + "\\bin\\sspi_bridge.dll" };
+                            } else {
+                                gssLibs = new String[0];
                             }
                         } else {
                             gssLibs = new String[]{ defaultLib };
@@ -103,8 +109,7 @@
                             if (GSSLibStub.init(libName, DEBUG)) {
                                 debug("Loaded GSS library: " + libName);
                                 Oid[] mechs = GSSLibStub.indicateMechs();
-                                HashMap<String, String> map =
-                                            new HashMap<String, String>();
+                                HashMap<String,String> map = new HashMap<>();
                                 for (int i = 0; i < mechs.length; i++) {
                                     debug("Native MF for " + mechs[i]);
                                     map.put("GssApiMechanism." + mechs[i],
--- a/src/java.security.jgss/share/native/libj2gss/GSSLibStub.c	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/java.security.jgss/share/native/libj2gss/GSSLibStub.c	Thu Jun 13 11:31:36 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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
@@ -982,7 +982,7 @@
   OM_uint32 aFlags;
   OM_uint32 aTime;
   gss_cred_id_t delCred;
-  jobject jsrcName=GSS_C_NO_NAME;
+  jobject jsrcName = NULL;
   jobject jdelCred;
   jobject jMech;
   jboolean setTarget;
--- a/src/java.security.jgss/share/native/libj2gss/NativeFunc.h	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/java.security.jgss/share/native/libj2gss/NativeFunc.h	Thu Jun 13 11:31:36 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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
@@ -57,38 +57,38 @@
 
 typedef OM_uint32 (*IMPORT_NAME_FN_PTR)
                                 (OM_uint32 *minor_status,
-                                gss_buffer_t input_name_buffer,
-                                gss_OID input_name_type,
+                                const gss_buffer_t input_name_buffer,
+                                const gss_OID input_name_type,
                                 gss_name_t *output_name);
 
 typedef OM_uint32 (*COMPARE_NAME_FN_PTR)
                                 (OM_uint32 *minor_status,
-                                gss_name_t name1,
-                                gss_name_t name2,
+                                gss_const_name_t name1,
+                                gss_const_name_t name2,
                                 int *name_equal);
 
 typedef OM_uint32 (*CANONICALIZE_NAME_FN_PTR)
                                 (OM_uint32 *minor_status,
-                                gss_name_t input_name,
-                                gss_OID mech_type,
+                                gss_const_name_t input_name,
+                                const gss_OID mech_type,
                                 gss_name_t *output_name);
 
 typedef OM_uint32 (*EXPORT_NAME_FN_PTR)
                                 (OM_uint32 *minor_status,
-                                gss_name_t input_name,
+                                gss_const_name_t input_name,
                                 gss_buffer_t exported_name);
 
 typedef OM_uint32 (*DISPLAY_NAME_FN_PTR)
                                 (OM_uint32 *minor_status,
-                                gss_name_t input_name,
+                                gss_const_name_t input_name,
                                 gss_buffer_t output_name_buffer,
                                 gss_OID *output_name_type);
 
 typedef OM_uint32 (*ACQUIRE_CRED_FN_PTR)
                                 (OM_uint32 *minor_status,
-                                gss_name_t desired_name,
+                                gss_const_name_t desired_name,
                                 OM_uint32 time_req,
-                                gss_OID_set desired_mech,
+                                const gss_OID_set desired_mech,
                                 gss_cred_usage_t cred_usage,
                                 gss_cred_id_t *output_cred_handle,
                                 gss_OID_set *actual_mechs,
@@ -100,7 +100,7 @@
 
 typedef OM_uint32 (*INQUIRE_CRED_FN_PTR)
                                 (OM_uint32 *minor_status,
-                                gss_cred_id_t cred_handle,
+                                gss_const_cred_id_t cred_handle,
                                 gss_name_t *name,
                                 OM_uint32 *lifetime,
                                 gss_cred_usage_t *cred_usage,
@@ -108,19 +108,19 @@
 
 typedef OM_uint32 (*IMPORT_SEC_CONTEXT_FN_PTR)
                                 (OM_uint32 *minor_status,
-                                gss_buffer_t interprocess_token,
+                                const gss_buffer_t interprocess_token,
                                 gss_ctx_id_t *context_handle);
 
 typedef OM_uint32 (*INIT_SEC_CONTEXT_FN_PTR)
                                 (OM_uint32 *minor_status,
-                                gss_cred_id_t initiator_cred_handle,
+                                gss_const_cred_id_t initiator_cred_handle,
                                 gss_ctx_id_t *context_handle,
-                                gss_name_t *target_name,
-                                gss_OID mech_type,
+                                gss_const_name_t target_name,
+                                const gss_OID mech_type,
                                 OM_uint32 req_flags,
                                 OM_uint32 time_req,
-                                gss_channel_bindings_t input_chan_bindings,
-                                gss_buffer_t input_token,
+                                const gss_channel_bindings_t input_chan_bindings,
+                                const gss_buffer_t input_token,
                                 gss_OID *actual_mech_type,
                                 gss_buffer_t output_token,
                                 OM_uint32 *ret_flags,
@@ -129,9 +129,9 @@
 typedef OM_uint32 (*ACCEPT_SEC_CONTEXT_FN_PTR)
                                 (OM_uint32 *minor_status,
                                 gss_ctx_id_t *context_handle,
-                                gss_cred_id_t acceptor_cred_handle,
-                                gss_buffer_t input_token,
-                                gss_channel_bindings_t input_chan_bindings,
+                                gss_const_cred_id_t acceptor_cred_handle,
+                                const gss_buffer_t input_token,
+                                const gss_channel_bindings_t input_chan_bindings,
                                 gss_name_t *src_name,
                                 gss_OID *mech_type,
                                 gss_buffer_t output_token,
@@ -141,7 +141,7 @@
 
 typedef OM_uint32 (*INQUIRE_CONTEXT_FN_PTR)
                                 (OM_uint32 *minor_status,
-                                gss_ctx_id_t context_handle,
+                                gss_const_ctx_id_t context_handle,
                                 gss_name_t *src_name,
                                 gss_name_t *targ_name,
                                 OM_uint32 *lifetime_rec,
@@ -157,12 +157,12 @@
 
 typedef OM_uint32 (*CONTEXT_TIME_FN_PTR)
                                 (OM_uint32 *minor_status,
-                                gss_ctx_id_t *context_handle,
+                                gss_const_ctx_id_t context_handle,
                                 OM_uint32 *time_rec);
 
 typedef OM_uint32 (*WRAP_SIZE_LIMIT_FN_PTR)
                                 (OM_uint32 *minor_status,
-                                gss_ctx_id_t context_handle,
+                                gss_const_ctx_id_t context_handle,
                                 int conf_req_flag,
                                 gss_qop_t qop_req,
                                 OM_uint32 req_output_size,
@@ -175,31 +175,31 @@
 
 typedef OM_uint32 (*GET_MIC_FN_PTR)
                                 (OM_uint32 *minor_status,
-                                gss_ctx_id_t context_handle,
+                                gss_const_ctx_id_t context_handle,
                                 gss_qop_t qop_req,
-                                gss_buffer_t message_buffer,
+                                const gss_buffer_t message_buffer,
                                 gss_buffer_t msg_token);
 
 typedef OM_uint32 (*VERIFY_MIC_FN_PTR)
                                 (OM_uint32 *minor_status,
-                                gss_ctx_id_t context_handle,
-                                gss_buffer_t message_buffer,
-                                gss_buffer_t token_buffer,
+                                gss_const_ctx_id_t context_handle,
+                                const gss_buffer_t message_buffer,
+                                const gss_buffer_t token_buffer,
                                 gss_qop_t *qop_state);
 
 typedef OM_uint32 (*WRAP_FN_PTR)
                                 (OM_uint32 *minor_status,
-                                gss_ctx_id_t context_handle,
+                                gss_const_ctx_id_t context_handle,
                                 int conf_req_flag,
                                 gss_qop_t qop_req,
-                                gss_buffer_t input_message_buffer,
+                                const gss_buffer_t input_message_buffer,
                                 int *conf_state,
                                 gss_buffer_t output_message_buffer);
 
 typedef OM_uint32 (*UNWRAP_FN_PTR)
                                 (OM_uint32 *minor_status,
-                                gss_ctx_id_t context_handle,
-                                gss_buffer_t input_message_buffer,
+                                gss_const_ctx_id_t context_handle,
+                                const gss_buffer_t input_message_buffer,
                                 gss_buffer_t output_message_buffer,
                                 int *conf_state,
                                 gss_qop_t *qop_state);
@@ -215,14 +215,14 @@
 
 typedef OM_uint32 (*ADD_OID_SET_MEMBER_FN_PTR)
                                 (OM_uint32 *minor_status,
-                                gss_OID member_oid,
+                                const gss_OID member_oid,
                                 gss_OID_set *oid_set);
 
 typedef OM_uint32 (*DISPLAY_STATUS_FN_PTR)
                                 (OM_uint32 *minor_status,
                                 OM_uint32 status_value,
                                 int status_type,
-                                gss_OID mech_type,
+                                const gss_OID mech_type,
                                 OM_uint32 *message_context,
                                 gss_buffer_t status_string);
 
--- a/src/java.security.jgss/share/native/libj2gss/NativeUtil.h	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/java.security.jgss/share/native/libj2gss/NativeUtil.h	Thu Jun 13 11:31:36 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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
@@ -83,10 +83,10 @@
   extern jfieldID FID_NativeGSSContext_flags;
   extern jfieldID FID_NativeGSSContext_lifetime;
   extern jfieldID FID_NativeGSSContext_actualMech;
-  #define TRACE0(s) { if (JGSS_DEBUG) { puts(s); fflush(stdout); }}
-  #define TRACE1(s, p1) { if (JGSS_DEBUG) { printf(s"\n", p1); fflush(stdout); }}
-  #define TRACE2(s, p1, p2) { if (JGSS_DEBUG) { printf(s"\n", p1, p2); fflush(stdout); }}
-  #define TRACE3(s, p1, p2, p3) { if (JGSS_DEBUG) { printf(s"\n", p1, p2, p3); fflush(stdout); }}
+  #define TRACE0(s) { if (JGSS_DEBUG) { printf("[GSSLibStub:%d] %s\n", __LINE__, s); fflush(stdout); }}
+  #define TRACE1(s, p1) { if (JGSS_DEBUG) { printf("[GSSLibStub:%d] "s"\n", __LINE__, p1); fflush(stdout); }}
+  #define TRACE2(s, p1, p2) { if (JGSS_DEBUG) { printf("[GSSLibStub:%d] "s"\n", __LINE__, p1, p2); fflush(stdout); }}
+  #define TRACE3(s, p1, p2, p3) { if (JGSS_DEBUG) { printf("[GSSLibStub:%d] "s"\n", __LINE__, p1, p2, p3); fflush(stdout); }}
 
 
 #ifdef __cplusplus
--- a/src/java.security.jgss/share/native/libj2gss/gssapi.h	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/java.security.jgss/share/native/libj2gss/gssapi.h	Thu Jun 13 11:31:36 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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
@@ -57,9 +57,17 @@
  */
 #include <sys/types.h>
 
-typedef void * gss_name_t;
-typedef void * gss_cred_id_t;
-typedef void * gss_ctx_id_t;
+struct gss_name_struct;
+typedef struct gss_name_struct * gss_name_t;
+typedef const struct gss_name_struct *gss_const_name_t;
+
+struct gss_cred_id_struct;
+typedef struct gss_cred_id_struct * gss_cred_id_t;
+typedef const struct gss_cred_id_struct *gss_const_cred_id_t;
+
+struct gss_ctx_id_struct;
+typedef struct gss_ctx_id_struct * gss_ctx_id_t;
+typedef const struct gss_ctx_id_struct *gss_const_ctx_id_t;
 
 /*
  * The following type must be defined as the smallest natural unsigned integer
@@ -82,16 +90,19 @@
       OM_uint32 length;
       void *elements;
 } gss_OID_desc, *gss_OID;
+typedef const gss_OID_desc * gss_const_OID;
 
 typedef struct gss_OID_set_desc_struct  {
       size_t  count;
       gss_OID elements;
 } gss_OID_set_desc, *gss_OID_set;
+typedef const gss_OID_set_desc * gss_const_OID_set;
 
 typedef struct gss_buffer_desc_struct {
       size_t length;
       void *value;
 } gss_buffer_desc, *gss_buffer_t;
+typedef const gss_buffer_desc * gss_const_buffer_t;
 
 typedef struct gss_channel_bindings_struct {
       OM_uint32 initiator_addrtype;
@@ -100,6 +111,7 @@
       gss_buffer_desc acceptor_address;
       gss_buffer_desc application_data;
 } *gss_channel_bindings_t;
+typedef const struct gss_channel_bindings_struct *gss_const_channel_bindings_t;
 
 /*
  * For now, define a QOP-type as an OM_uint32
@@ -119,6 +131,7 @@
 #define GSS_C_ANON_FLAG 64
 #define GSS_C_PROT_READY_FLAG 128
 #define GSS_C_TRANS_FLAG 256
+#define GSS_C_DELEG_POLICY_FLAG 32768
 
 /*
  * Credential usage options
@@ -389,9 +402,9 @@
 
 GSS_DLLIMP OM_uint32 gss_acquire_cred(
         OM_uint32 *,            /* minor_status */
-        gss_name_t,             /* desired_name */
+        gss_const_name_t,       /* desired_name */
         OM_uint32,              /* time_req */
-        gss_OID_set,            /* desired_mechs */
+        const gss_OID_set,      /* desired_mechs */
         gss_cred_usage_t,       /* cred_usage */
         gss_cred_id_t *,        /* output_cred_handle */
         gss_OID_set *,          /* actual_mechs */
@@ -405,14 +418,14 @@
 
 GSS_DLLIMP OM_uint32 gss_init_sec_context(
         OM_uint32 *,            /* minor_status */
-        gss_cred_id_t,          /* claimant_cred_handle */
+        gss_const_cred_id_t,    /* claimant_cred_handle */
         gss_ctx_id_t *,         /* context_handle */
-        gss_name_t,             /* target_name */
-        gss_OID,                /* mech_type (used to be const) */
+        gss_const_name_t,       /* target_name */
+        const gss_OID,          /* mech_type */
         OM_uint32,              /* req_flags */
         OM_uint32,              /* time_req */
-        gss_channel_bindings_t, /* input_chan_bindings */
-        gss_buffer_t,           /* input_token */
+        const gss_channel_bindings_t, /* input_chan_bindings */
+        const gss_buffer_t,     /* input_token */
         gss_OID *,              /* actual_mech_type */
         gss_buffer_t,           /* output_token */
         OM_uint32 *,            /* ret_flags */
@@ -422,9 +435,9 @@
 GSS_DLLIMP OM_uint32 gss_accept_sec_context(
         OM_uint32 *,            /* minor_status */
         gss_ctx_id_t *,         /* context_handle */
-        gss_cred_id_t,          /* acceptor_cred_handle */
-        gss_buffer_t,           /* input_token_buffer */
-        gss_channel_bindings_t, /* input_chan_bindings */
+        gss_const_cred_id_t,    /* acceptor_cred_handle */
+        const gss_buffer_t,     /* input_token_buffer */
+        const gss_channel_bindings_t, /* input_chan_bindings */
         gss_name_t *,           /* src_name */
         gss_OID *,              /* mech_type */
         gss_buffer_t,           /* output_token */
@@ -435,8 +448,8 @@
 
 GSS_DLLIMP OM_uint32 gss_process_context_token(
         OM_uint32 *,            /* minor_status */
-        gss_ctx_id_t,           /* context_handle */
-        gss_buffer_t            /* token_buffer */
+        gss_const_ctx_id_t,     /* context_handle */
+        const gss_buffer_t      /* token_buffer */
 );
 
 GSS_DLLIMP OM_uint32 gss_delete_sec_context(
@@ -447,35 +460,35 @@
 
 GSS_DLLIMP OM_uint32 gss_context_time(
         OM_uint32 *,            /* minor_status */
-        gss_ctx_id_t,           /* context_handle */
+        gss_const_ctx_id_t,     /* context_handle */
         OM_uint32 *             /* time_rec */
 );
 
 /* New for V2 */
 GSS_DLLIMP OM_uint32 gss_get_mic(
         OM_uint32 *,            /* minor_status */
-        gss_ctx_id_t,           /* context_handle */
+        gss_const_ctx_id_t,     /* context_handle */
         gss_qop_t,              /* qop_req */
-        gss_buffer_t,           /* message_buffer */
+        const gss_buffer_t,     /* message_buffer */
         gss_buffer_t            /* message_token */
 );
 
 /* New for V2 */
 GSS_DLLIMP OM_uint32 gss_verify_mic(
         OM_uint32 *,            /* minor_status */
-        gss_ctx_id_t,           /* context_handle */
-        gss_buffer_t,           /* message_buffer */
-        gss_buffer_t,           /* message_token */
+        gss_const_ctx_id_t,     /* context_handle */
+        const gss_buffer_t,     /* message_buffer */
+        const gss_buffer_t,     /* message_token */
         gss_qop_t *             /* qop_state */
 );
 
 /* New for V2 */
 GSS_DLLIMP OM_uint32 gss_wrap(
         OM_uint32 *,            /* minor_status */
-        gss_ctx_id_t,           /* context_handle */
+        gss_const_ctx_id_t,     /* context_handle */
         int,                    /* conf_req_flag */
         gss_qop_t,              /* qop_req */
-        gss_buffer_t,           /* input_message_buffer */
+        const gss_buffer_t,     /* input_message_buffer */
         int *,                  /* conf_state */
         gss_buffer_t            /* output_message_buffer */
 );
@@ -483,8 +496,8 @@
 /* New for V2 */
 GSS_DLLIMP OM_uint32 gss_unwrap(
         OM_uint32 *,            /* minor_status */
-        gss_ctx_id_t,           /* context_handle */
-        gss_buffer_t,           /* input_message_buffer */
+        gss_const_ctx_id_t,     /* context_handle */
+        const gss_buffer_t,     /* input_message_buffer */
         gss_buffer_t,           /* output_message_buffer */
         int *,                  /* conf_state */
         gss_qop_t *             /* qop_state */
@@ -494,7 +507,7 @@
         OM_uint32 *,            /* minor_status */
         OM_uint32,              /* status_value */
         int,                    /* status_type */
-        gss_OID,                /* mech_type (used to be const) */
+        const gss_OID,          /* mech_type (used to be const) */
         OM_uint32 *,            /* message_context */
         gss_buffer_t            /* status_string */
 );
@@ -506,22 +519,22 @@
 
 GSS_DLLIMP OM_uint32 gss_compare_name(
         OM_uint32 *,            /* minor_status */
-        gss_name_t,             /* name1 */
-        gss_name_t,             /* name2 */
+        gss_const_name_t,       /* name1 */
+        gss_const_name_t,       /* name2 */
         int *                   /* name_equal */
 );
 
 GSS_DLLIMP OM_uint32 gss_display_name(
         OM_uint32 *,            /* minor_status */
-        gss_name_t,             /* input_name */
+        gss_const_name_t,       /* input_name */
         gss_buffer_t,           /* output_name_buffer */
         gss_OID *               /* output_name_type */
 );
 
 GSS_DLLIMP OM_uint32 gss_import_name(
         OM_uint32 *,            /* minor_status */
-        gss_buffer_t,           /* input_name_buffer */
-        gss_OID,                /* input_name_type(used to be const) */
+        const gss_buffer_t,     /* input_name_buffer */
+        const gss_OID,          /* input_name_type(used to be const) */
         gss_name_t *            /* output_name */
 );
 
@@ -542,7 +555,7 @@
 
 GSS_DLLIMP OM_uint32 gss_inquire_cred(
         OM_uint32 *,            /* minor_status */
-        gss_cred_id_t,          /* cred_handle */
+        gss_const_cred_id_t,    /* cred_handle */
         gss_name_t *,           /* name */
         OM_uint32 *,            /* lifetime */
         gss_cred_usage_t *,     /* cred_usage */
@@ -552,7 +565,7 @@
 /* Last argument new for V2 */
 GSS_DLLIMP OM_uint32 gss_inquire_context(
         OM_uint32 *,            /* minor_status */
-        gss_ctx_id_t,           /* context_handle */
+        gss_const_ctx_id_t,     /* context_handle */
         gss_name_t *,           /* src_name */
         gss_name_t *,           /* targ_name */
         OM_uint32 *,            /* lifetime_rec */
@@ -565,7 +578,7 @@
 /* New for V2 */
 GSS_DLLIMP OM_uint32 gss_wrap_size_limit(
         OM_uint32 *,            /* minor_status */
-        gss_ctx_id_t,           /* context_handle */
+        gss_const_ctx_id_t,     /* context_handle */
         int,                    /* conf_req_flag */
         gss_qop_t,              /* qop_req */
         OM_uint32,              /* req_output_size */
@@ -575,9 +588,9 @@
 /* New for V2 */
 GSS_DLLIMP OM_uint32 gss_add_cred(
         OM_uint32 *,            /* minor_status */
-        gss_cred_id_t,          /* input_cred_handle */
-        gss_name_t,             /* desired_name */
-        gss_OID,                /* desired_mech */
+        gss_const_cred_id_t,    /* input_cred_handle */
+        gss_const_name_t,       /* desired_name */
+        const gss_OID,          /* desired_mech */
         gss_cred_usage_t,       /* cred_usage */
         OM_uint32,              /* initiator_time_req */
         OM_uint32,              /* acceptor_time_req */
@@ -590,8 +603,8 @@
 /* New for V2 */
 GSS_DLLIMP OM_uint32 gss_inquire_cred_by_mech(
         OM_uint32 *,            /* minor_status */
-        gss_cred_id_t,          /* cred_handle */
-        gss_OID,                /* mech_type */
+        gss_const_cred_id_t,    /* cred_handle */
+        const gss_OID,          /* mech_type */
         gss_name_t *,           /* name */
         OM_uint32 *,            /* initiator_lifetime */
         OM_uint32 *,            /* acceptor_lifetime */
@@ -608,7 +621,7 @@
 /* New for V2 */
 GSS_DLLIMP OM_uint32 gss_import_sec_context(
         OM_uint32 *,            /* minor_status */
-        gss_buffer_t,           /* interprocess_token */
+        const gss_buffer_t,     /* interprocess_token */
         gss_ctx_id_t *          /* context_handle */
 );
 
@@ -627,22 +640,22 @@
 /* New for V2 */
 GSS_DLLIMP OM_uint32 gss_add_oid_set_member(
         OM_uint32 *,            /* minor_status */
-        gss_OID,                /* member_oid */
+        const gss_OID,          /* member_oid */
         gss_OID_set *           /* oid_set */
 );
 
 /* New for V2 */
 GSS_DLLIMP OM_uint32 gss_test_oid_set_member(
         OM_uint32 *,            /* minor_status */
-        gss_OID,                /* member */
-        gss_OID_set,            /* set */
+        const gss_OID,          /* member */
+        const gss_OID_set,      /* set */
         int *                   /* present */
 );
 
 /* New for V2 */
 GSS_DLLIMP OM_uint32 gss_str_to_oid(
         OM_uint32 *,            /* minor_status */
-        gss_buffer_t,           /* oid_str */
+        const gss_buffer_t,     /* oid_str */
         gss_OID *               /* oid */
 );
 
@@ -656,28 +669,28 @@
 /* New for V2 */
 GSS_DLLIMP OM_uint32 gss_inquire_names_for_mech(
         OM_uint32 *,            /* minor_status */
-        gss_OID,                /* mechanism */
+        const gss_OID,          /* mechanism */
         gss_OID_set *           /* name_types */
 );
 
 /* New for V2 */
 GSS_DLLIMP OM_uint32 gss_export_name(
         OM_uint32  *,           /* minor_status */
-        const gss_name_t,       /* input_name */
+        gss_const_name_t,       /* input_name */
         gss_buffer_t            /* exported_name */
 );
 
 /* New for V2 */
 GSS_DLLIMP OM_uint32 gss_duplicate_name(
         OM_uint32  *,           /* minor_status */
-        const gss_name_t,       /* input_name */
+        gss_const_name_t,       /* input_name */
         gss_name_t *            /* dest_name */
 );
 
 /* New for V2 */
 GSS_DLLIMP OM_uint32 gss_canonicalize_name(
         OM_uint32  *,           /* minor_status */
-        const gss_name_t,       /* input_name */
+        gss_const_name_t,       /* input_name */
         const gss_OID,          /* mech_type */
         gss_name_t *            /* output_name */
 );
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.security.jgss/windows/native/libsspi_bridge/sspi.cpp	Thu Jun 13 11:31:36 2019 +0530
@@ -0,0 +1,1575 @@
+/*
+ * 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.
+ */
+
+// This library is client-side only, and only supports the default credentials.
+// It speaks krb5 and SPNEGO. NTLM is excluded from SPNEGO negotiation.
+//
+// This library can be built directly with the following command:
+//   cl -I %OPENJDK%\src\java.security.jgss\share\native\libj2gss\ sspi.cpp \
+//      -link -dll -out:sspi_bridge.dll
+
+#define UNICODE
+#define _UNICODE
+
+#include <windows.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <Strsafe.h>
+#include <ntsecapi.h>
+#include <new>
+
+#define GSS_DLL_FILE
+#include <gssapi.h>
+
+#define SECURITY_WIN32
+#include <sspi.h>
+
+#pragma comment(lib, "secur32.lib")
+
+// Otherwise an exception will be thrown
+#define new new (std::nothrow)
+
+// A debugging macro
+#define PP(fmt, ...) \
+        if (trace) { \
+            fprintf(stderr, "[SSPI:%ld] "fmt"\n", __LINE__, ##__VA_ARGS__); \
+            fflush(stderr); \
+        }
+#define SEC_SUCCESS(status) ((*minor_status = (status)), (status) >= SEC_E_OK)
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+// When SSPI_BRIDGE_TRACE is set, debug info goes to stderr. The value is ignored.
+char* trace = getenv("SSPI_BRIDGE_TRACE");
+
+void
+dump(const char* title, PBYTE data, size_t len)
+{
+    if (trace) {
+        fprintf(stderr, "==== %s ====\n", title);
+        for (size_t i = 0; i < len; i++) {
+            if (i != 0 && i % 16 == 0) {
+                fprintf(stderr, "\n");
+            }
+            fprintf(stderr, "%02X ", *(data + i) & 0xff);
+        }
+        fprintf(stderr, "\n");
+    }
+}
+
+gss_OID_desc KRB5_OID = {9, (void*)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"};
+gss_OID_desc SPNEGO_OID = {6, (void*)"\x2b\x06\x01\x05\x05\x02"};
+gss_OID_desc USER_NAME_OID = {10, (void*)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x01"};
+gss_OID_desc KRB5_NAME_OID = {10, (void*)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01"};
+gss_OID_desc HOST_SERVICE_NAME_OID = {10, (void*)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04"};
+gss_OID_desc EXPORT_NAME_OID = {6, (void*)"\x2b\x06\x01\x05\x06\x04"};
+
+struct gss_name_struct {
+    SEC_WCHAR* name;
+};
+
+struct gss_ctx_id_struct {
+    CredHandle* phCred;
+    CtxtHandle hCtxt;
+    SecPkgContext_Sizes SecPkgContextSizes;
+    SecPkgContext_NativeNames nnames;
+    BOOLEAN established;
+    BOOLEAN isSPNEGO;
+    BOOLEAN isLocalCred;
+    OM_uint32 flags;
+};
+
+struct gss_cred_id_struct {
+    CredHandle* phCredK;
+    CredHandle* phCredS;
+    long time;
+};
+
+/* This section holds supporting functions that are not exported */
+
+static OM_uint32
+seconds_until(int inputIsUTC, TimeStamp *time)
+{
+    // time is local time
+    LARGE_INTEGER uiLocal;
+    FILETIME now;
+    GetSystemTimeAsFileTime(&now);
+    if (!inputIsUTC) {
+        FILETIME nowLocal;
+        if (FileTimeToLocalFileTime(&now, &nowLocal) == 0) {
+            return -1;
+        }
+        now = nowLocal;
+    }
+    uiLocal.HighPart = now.dwHighDateTime;
+    uiLocal.LowPart = now.dwLowDateTime;
+    if (time->QuadPart < uiLocal.QuadPart) {
+        return 0;
+    }
+    ULONGLONG diff = (time->QuadPart - uiLocal.QuadPart) / 10000000;
+    if (diff > (ULONGLONG)~(OM_uint32)0)
+        return GSS_C_INDEFINITE;
+    return (OM_uint32)diff;
+}
+
+static void
+show_time(char* label, TimeStamp* ts)
+{
+    if (trace) {
+        SYSTEMTIME stLocal;
+        FileTimeToSystemTime((FILETIME*)ts, &stLocal);
+
+        // Build a string showing the date and time.
+        PP("%s: %02d/%02d/%d  %02d:%02d %uld", label,
+            stLocal.wMonth, stLocal.wDay, stLocal.wYear,
+            stLocal.wHour, stLocal.wMinute,
+            seconds_until(1, ts));
+    }
+}
+
+// isSPNEGO: true, SPNEGO. false, Kerberos.
+static gss_ctx_id_t
+new_context(BOOLEAN isSPNEGO)
+{
+    gss_ctx_id_t out = new gss_ctx_id_struct;
+    if (out == NULL) {
+        return NULL;
+    }
+    out->phCred = NULL;
+    out->hCtxt.dwLower = out->hCtxt.dwUpper = NULL;
+    out->established = FALSE;
+    out->SecPkgContextSizes.cbMaxSignature
+            = out->SecPkgContextSizes.cbBlockSize
+            = out->SecPkgContextSizes.cbSecurityTrailer
+            = 0;
+    out->nnames.sClientName = out->nnames.sServerName = NULL;
+    out->isSPNEGO = isSPNEGO;
+    out->isLocalCred = FALSE;
+    return out;
+}
+
+static gss_cred_id_t
+new_cred()
+{
+    gss_cred_id_t out = new gss_cred_id_struct;
+    out->phCredK = out->phCredS = NULL;
+    out->time = 0L;
+    return out;
+}
+
+static int
+flag_sspi_to_gss(int fin)
+{
+    int fout = 0;
+    if (fin & ISC_REQ_MUTUAL_AUTH) fout |= GSS_C_MUTUAL_FLAG;
+    if (fin & ISC_REQ_CONFIDENTIALITY) fout |= GSS_C_CONF_FLAG;
+    if (fin & ISC_REQ_DELEGATE) fout |= GSS_C_DELEG_FLAG;
+    if (fin & ISC_REQ_INTEGRITY) fout |= GSS_C_INTEG_FLAG;
+    if (fin & ISC_REQ_REPLAY_DETECT) fout |= GSS_C_REPLAY_FLAG;
+    if (fin & ISC_REQ_SEQUENCE_DETECT) fout |= GSS_C_SEQUENCE_FLAG;
+    return fout;
+}
+
+static int
+flag_gss_to_sspi(int fin)
+{
+    int fout = 0;
+    if (fin & GSS_C_MUTUAL_FLAG) fout |= ISC_RET_MUTUAL_AUTH;
+    if (fin & GSS_C_CONF_FLAG) fout |= ISC_RET_CONFIDENTIALITY;
+    if (fin & GSS_C_DELEG_FLAG) fout |= ISC_RET_DELEGATE;
+    if (fin & GSS_C_INTEG_FLAG) fout |= ISC_RET_INTEGRITY;
+    if (fin & GSS_C_REPLAY_FLAG) fout |= ISC_RET_REPLAY_DETECT;
+    if (fin & GSS_C_SEQUENCE_FLAG) fout |= ISC_RET_SEQUENCE_DETECT;
+    return fout;
+}
+
+static BOOLEAN
+is_same_oid(gss_OID o2, gss_OID o1)
+{
+    return o1 && o2 && o1->length == o2->length
+            && !memcmp(o1->elements, o2->elements, o2->length);
+}
+
+static BOOLEAN
+has_oid(gss_OID_set set, gss_OID oid)
+{
+    for (int i = 0; i < set->count; i++) {
+        if (is_same_oid(&set->elements[i], oid)) {
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+static void
+get_oid_desc(gss_OID mech)
+{
+    if (trace) {
+        if (is_same_oid(mech, &KRB5_OID)) {
+            PP("Kerberos mech");
+        } else if (is_same_oid(mech, &SPNEGO_OID)) {
+            PP("SPNEGO mech");
+        } else if (is_same_oid(mech, &USER_NAME_OID)) {
+            PP("NT_USER_NAME name-type");
+        } else if (is_same_oid(mech, &KRB5_NAME_OID)) {
+            PP("KRB5_NAME name-type");
+        } else if (is_same_oid(mech, &HOST_SERVICE_NAME_OID)) {
+            PP("NT_HOSTBASED_SERVICE name-type");
+        } else if (is_same_oid(mech, &EXPORT_NAME_OID)) {
+            PP("NT_EXPORT_NAME name-type");
+        } else {
+            dump("UNKNOWN OID", (PBYTE)mech->elements, mech->length);
+        }
+    }
+}
+
+static void
+get_oid_set_desc(gss_OID_set mechs)
+{
+    if (trace) {
+        if (mechs == NULL) {
+            PP("OID set is NULL");
+            return;
+        }
+        PP("gss_OID_set.count is %d", (int)mechs->count);
+        for (int i = 0; i < mechs->count; i++) {
+            get_oid_desc(&mechs->elements[i]);
+        }
+    }
+}
+
+// Add realm to a name if there was none.
+// Returns a newly allocated name.
+static WCHAR*
+get_full_name(WCHAR* input)
+{
+    // input has realm, no need to add one
+    for (int i = 0;; i++) {
+        if (!input[i]) { // the end
+            break;
+        }
+        if (input[i] == L'\\') { // escaped
+            i++;
+            continue;
+        }
+        if (input[i] == L'@') {
+            return _wcsdup(input);
+        }
+    }
+
+    // Always use the default domain
+    WCHAR* realm = _wgetenv(L"USERDNSDOMAIN");
+    if (realm == NULL) {
+        realm = L"";
+    }
+
+    size_t oldlen = wcslen(input);
+    size_t newlen = oldlen + 1 + wcslen(realm) + 1;
+
+    WCHAR* fullname = new WCHAR[newlen];
+    if (!fullname) {
+        return NULL;
+    }
+    wcscpy_s(fullname, newlen, input);
+    wcscat_s(fullname, newlen, L"@");
+    wcscat_s(fullname, newlen, realm);
+
+    PP("get_full_name returns %ls", fullname);
+    return fullname;
+}
+
+/* End support section */
+
+/* This section holds GSS-API exported functions */
+
+#define CHECK_OUTPUT(x)  if (!x) return GSS_S_CALL_INACCESSIBLE_WRITE;
+#define CHECK_BUFFER(b)  if (!b || !b->value) return GSS_S_CALL_INACCESSIBLE_READ;
+#define CHECK_OID(o)     if (!o || !o->elements) return GSS_S_CALL_INACCESSIBLE_READ;
+#define CHECK_NAME(n)    if (!n || !(n->name)) return GSS_S_BAD_NAME;
+#define CHECK_CONTEXT(c) if (!c) return GSS_S_NO_CONTEXT;
+#define CHECK_CRED(c)    if (!c || (!(cred_handle->phCredK) && !(cred_handle->phCredS))) \
+                                return GSS_S_NO_CRED;
+
+__declspec(dllexport) OM_uint32
+gss_release_name(OM_uint32 *minor_status,
+                 gss_name_t *name)
+{
+    PP(">>>> Calling gss_release_name %p...", *name);
+    if (name != NULL && *name != GSS_C_NO_NAME) {
+        if ((*name)->name != NULL) {
+            delete[] (*name)->name;
+        }
+        delete *name;
+        *name = GSS_C_NO_NAME;
+    }
+    return GSS_S_COMPLETE;
+}
+
+__declspec(dllexport) OM_uint32
+gss_import_name(OM_uint32 *minor_status,
+                const gss_buffer_t input_name_buffer,
+                const gss_OID input_name_type,
+                gss_name_t *output_name)
+{
+    PP(">>>> Calling gss_import_name...");
+    CHECK_BUFFER(input_name_buffer)
+    CHECK_OUTPUT(output_name)
+
+    int len = (int)input_name_buffer->length;
+    LPSTR input = (LPSTR)input_name_buffer->value;
+    if (input_name_type != NULL
+            && is_same_oid(input_name_type, &EXPORT_NAME_OID)) {
+        int mechLen = (int)input[3]; /* including 06 len */
+        len -= mechLen + 8; /* 4 header bytes, and an int32 length after OID */
+        if (len <= 0) {
+            return GSS_S_FAILURE;
+        }
+        // Reject if mech is not krb5
+        if (mechLen - 2!= KRB5_OID.length ||
+                memcmp(input + 6, KRB5_OID.elements, mechLen - 2)) {
+            return GSS_S_FAILURE;;
+        }
+        input = input + mechLen + 8;
+    }
+
+    SEC_WCHAR* value = new SEC_WCHAR[len + 1];
+    if (value == NULL) {
+        goto err;
+    }
+
+    len = MultiByteToWideChar(CP_UTF8, 0, input, len, value, len+1);
+    if (len == 0) {
+        goto err;
+    }
+    value[len] = 0;
+
+    PP("import_name from %ls", value);
+
+    if (len > 33 && !wcscmp(value+len-33, L"@WELLKNOWN:ORG.H5L.REFERALS-REALM")) {
+        // Remove the wellknown referrals realms
+        value[len-33] = 0;
+        len -= 33;
+    } else if (value[len-1] == L'@') {
+        // Remove the empty realm. It might come from an NT_EXPORT_NAME.
+        value[len-1] = 0;
+        len--;
+    }
+    if (len == 0) {
+        goto err;
+    }
+
+    if (input_name_type != NULL
+            && is_same_oid(input_name_type, &HOST_SERVICE_NAME_OID)) {
+        // HOST_SERVICE_NAME_OID takes the form of service@host.
+        for (int i = 0; i < len; i++) {
+            if (value[i] == L'\\') {
+                i++;
+                continue;
+            }
+            if (value[i] == L'@') {
+                value[i] = L'/';
+                break;
+            }
+        }
+        PP("Host-based service now %ls", value);
+    }
+    PP("import_name to %ls", value);
+    gss_name_struct* name = new gss_name_struct;
+    if (name == NULL) {
+        goto err;
+    }
+    name->name = value;
+    *output_name = (gss_name_t) name;
+    return GSS_S_COMPLETE;
+err:
+    if (value != NULL) {
+        delete[] value;
+    }
+    return GSS_S_FAILURE;
+}
+
+__declspec(dllexport) OM_uint32
+gss_compare_name(OM_uint32 *minor_status,
+                 gss_const_name_t name1,
+                 gss_const_name_t name2,
+                 int *name_equal)
+{
+    PP(">>>> Calling gss_compare_name...");
+    CHECK_NAME(name1)
+    CHECK_NAME(name2)
+    CHECK_OUTPUT(name_equal)
+
+    *name_equal = 0;
+
+    SEC_WCHAR* n1 = name1->name;
+    SEC_WCHAR* n2 = name2->name;
+    PP("Comparing %ls and %ls", n1, n2);
+    int l1 = lstrlen(n1);
+    int l2 = lstrlen(n2);
+    if (l1 < l2 && n2[l1] != L'@'
+            || l2 < l1 && n1[l2] != L'@') {
+        return GSS_S_COMPLETE; // different
+    }
+    if (l1 > l2) {
+        l1 = l2; // choose the smaller one. longer=smaller @ ...
+    }
+    if (CompareStringEx(LOCALE_NAME_SYSTEM_DEFAULT, NORM_IGNORECASE,
+            n1, l1, n2, l1, NULL, NULL, 0) == CSTR_EQUAL) {
+        *name_equal = 1;
+    }
+    return GSS_S_COMPLETE;
+}
+
+__declspec(dllexport) OM_uint32
+gss_canonicalize_name(OM_uint32 *minor_status,
+                      gss_const_name_t input_name,
+                      const gss_OID mech_type,
+                      gss_name_t *output_name)
+{
+    PP(">>>> Calling gss_canonicalize_name...");
+    CHECK_NAME(input_name)
+    CHECK_OID(mech_type)
+    CHECK_OUTPUT(output_name)
+
+    gss_name_t names2 = new gss_name_struct;
+    if (names2 == NULL) {
+        return GSS_S_FAILURE;
+    }
+    names2->name = get_full_name(input_name->name);
+    if (names2->name == NULL) {
+        delete names2;
+        return GSS_S_FAILURE;
+    }
+    *output_name = names2;
+    return GSS_S_COMPLETE;
+}
+
+__declspec(dllexport) OM_uint32
+gss_export_name(OM_uint32 *minor_status,
+                gss_const_name_t input_name,
+                gss_buffer_t exported_name)
+{
+    PP(">>>> Calling gss_export_name...");
+    CHECK_NAME(input_name)
+    CHECK_OUTPUT(exported_name)
+
+    OM_uint32 result = GSS_S_FAILURE;
+    SEC_WCHAR* name = input_name->name;
+    SEC_WCHAR* fullname = get_full_name(name);
+    if (!fullname) {
+        goto err;
+    }
+    PP("Make fullname: %ls -> %ls", name, fullname);
+    int len;
+    size_t namelen = wcslen(fullname);
+    if (namelen > 255) {
+        goto err;
+    }
+    len = (int)namelen;
+    // We only deal with not-so-long names.
+    // 04 01 00 ** 06 ** OID len:int32 name
+    int mechLen = KRB5_OID.length;
+    char* buffer = new char[10 + mechLen + len];
+    if (buffer == NULL) {
+        goto err;
+    }
+    buffer[0] = 4;
+    buffer[1] = 1;
+    buffer[2] = 0;
+    buffer[3] = 2 + mechLen;
+    buffer[4] = 6;
+    buffer[5] = mechLen;
+    memcpy_s(buffer + 6, mechLen, KRB5_OID.elements, mechLen);
+    buffer[6 + mechLen] = buffer[7 + mechLen] = buffer[8 + mechLen] = 0;
+    buffer[9 + mechLen] = (char)len;
+    len = WideCharToMultiByte(CP_UTF8, 0, fullname, len,
+                buffer+10+mechLen, len, NULL, NULL);
+    if (len == 0) {
+        delete[] buffer;
+        goto err;
+    }
+    exported_name->length = 10 + mechLen + len;
+    exported_name->value = buffer;
+    result = GSS_S_COMPLETE;
+err:
+    if (fullname != name) {
+        delete[] fullname;
+    }
+    return result;
+}
+
+__declspec(dllexport) OM_uint32
+gss_display_name(OM_uint32 *minor_status,
+                 gss_const_name_t input_name,
+                 gss_buffer_t output_name_buffer,
+                 gss_OID *output_name_type)
+{
+    PP(">>>> Calling gss_display_name...");
+    CHECK_NAME(input_name)
+    CHECK_OUTPUT(output_name_buffer)
+
+    SEC_WCHAR* names = input_name->name;
+    int len = (int)wcslen(names);
+    char* buffer = new char[4*len+1];
+    if (buffer == NULL) {
+        return GSS_S_FAILURE;
+    }
+    len = WideCharToMultiByte(CP_UTF8, 0, names, len, buffer, 4*len, NULL, NULL);
+    if (len == 0) {
+        delete[] buffer;
+        return GSS_S_FAILURE;
+    }
+    buffer[len] = 0;
+    output_name_buffer->length = len;
+    output_name_buffer->value = buffer;
+    PP("Name found: %ls -> %d [%s]", names, len, buffer);
+    if (output_name_type != NULL) {
+        *output_name_type = &KRB5_NAME_OID;
+    }
+    return GSS_S_COMPLETE;
+}
+
+__declspec(dllexport) OM_uint32
+gss_acquire_cred(OM_uint32 *minor_status,
+                 gss_const_name_t desired_name,
+                 OM_uint32 time_req,
+                 const gss_OID_set desired_mechs,
+                 gss_cred_usage_t cred_usage,
+                 gss_cred_id_t *output_cred_handle,
+                 gss_OID_set *actual_mechs,
+                 OM_uint32 *time_rec)
+{
+    PP(">>>> Calling gss_acquire_cred...");
+    CHECK_OUTPUT(output_cred_handle)
+
+    SECURITY_STATUS ss;
+    TimeStamp ts;
+    ts.QuadPart = 0;
+    cred_usage = 0;
+    PP("AcquireCredentialsHandle with %d %p", cred_usage, desired_mechs);
+    get_oid_set_desc(desired_mechs);
+
+    BOOLEAN reqKerberos, reqSPNEGO;
+
+    if (!desired_mechs) {
+        reqKerberos = reqSPNEGO = TRUE;
+    } else {
+        if (has_oid(desired_mechs, &KRB5_OID)) {
+            PP("reqKerberos");
+            reqKerberos = TRUE;
+        }
+        if (has_oid(desired_mechs, &SPNEGO_OID)) {
+            PP("reqSPNEGO");
+            reqSPNEGO = TRUE;
+        }
+        if (!reqSPNEGO && !reqKerberos) {
+            return GSS_S_BAD_MECH;
+        }
+    }
+
+    if (actual_mechs) {
+        *actual_mechs = GSS_C_NO_OID_SET;
+    }
+
+    gss_cred_id_t cred = new_cred();
+    if (cred == NULL) {
+        goto err;
+    }
+
+    if (reqKerberos) {
+        cred->phCredK = new CredHandle;
+        if (cred->phCredK == NULL) {
+            goto err;
+        }
+        ss = AcquireCredentialsHandle(
+                NULL,
+                L"Kerberos",
+                cred_usage == 0 ? SECPKG_CRED_BOTH :
+                    (cred_usage == 1 ? SECPKG_CRED_OUTBOUND : SECPKG_CRED_INBOUND),
+                NULL,
+                NULL,
+                NULL,
+                NULL,
+                cred->phCredK,
+                &ts);
+        if (!(SEC_SUCCESS(ss))) {
+            delete cred->phCredK;
+            cred->phCredK = NULL;
+            goto err;
+        }
+    }
+
+    if (reqSPNEGO) {
+        cred->phCredS = new CredHandle;
+        if (cred->phCredS == NULL) {
+            goto err;
+        }
+        SEC_WINNT_AUTH_IDENTITY_EX auth;
+        ZeroMemory(&auth, sizeof(auth));
+        auth.Version = SEC_WINNT_AUTH_IDENTITY_VERSION;
+        auth.Length = sizeof(auth);
+        auth.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
+        auth.PackageList = (unsigned short*)L"Kerberos";
+        auth.PackageListLength = 8;
+        ss = AcquireCredentialsHandle(
+                NULL,
+                L"Negotiate",
+                cred_usage == 0 ? SECPKG_CRED_BOTH :
+                    (cred_usage == 1 ? SECPKG_CRED_OUTBOUND : SECPKG_CRED_INBOUND),
+                NULL,
+                &auth,
+                NULL,
+                NULL,
+                cred->phCredS,
+                &ts);
+        if (!(SEC_SUCCESS(ss))) {
+            delete cred->phCredS;
+            cred->phCredS = NULL;
+            goto err;
+        }
+    }
+
+    if (actual_mechs) {
+        if (gss_create_empty_oid_set(minor_status, actual_mechs)) {
+            goto err;
+        }
+        if (reqKerberos) {
+            if (gss_add_oid_set_member(minor_status, &KRB5_OID, actual_mechs)) {
+                goto err;
+            }
+        }
+        if (reqSPNEGO) {
+            if (gss_add_oid_set_member(minor_status, &SPNEGO_OID, actual_mechs)) {
+                goto err;
+            }
+        }
+    }
+
+    *output_cred_handle = (gss_cred_id_t)cred;
+
+    // Note: ts here is weirdly huge, maybe because LSA retains the
+    // password and can re-acquire a TGT at anytime. It will be
+    // GSSCredential.INDEFINITE_LIFETIME.
+    show_time("cred expiration", &ts);
+    cred->time = seconds_until(1, &ts);
+    if (time_rec != NULL) {
+        *time_rec = cred->time;
+    }
+
+    // Since only default cred is supported, if there is a desired_name,
+    // we must make sure it is the same as the realname of the default cred.
+    if (desired_name != NULL) {
+        PP("Acquiring cred with a name. Check if it's me.");
+        gss_name_t realname;
+        if (gss_inquire_cred(minor_status, *output_cred_handle, &realname,
+                NULL, NULL, NULL) != GSS_S_COMPLETE) {
+            PP("Cannot get owner name of default creds");
+            goto err;
+        }
+        SEC_WCHAR* rnames = realname->name;
+        SEC_WCHAR* dnames = desired_name->name;
+        int equals = 0;
+        gss_compare_name(minor_status, realname, desired_name, &equals);
+        gss_release_name(minor_status, &realname);
+        PP("Comparing result: %d", equals);
+        if (!equals) {
+            goto err;
+        }
+    }
+
+    return GSS_S_COMPLETE;
+err:
+    if (cred) {
+        OM_uint32 dummy;
+        gss_release_cred(&dummy, &cred);
+    }
+    if (actual_mechs) {
+        OM_uint32 dummy;
+        gss_release_oid_set(&dummy, actual_mechs);
+    }
+    return GSS_S_FAILURE;
+}
+
+__declspec(dllexport) OM_uint32
+gss_release_cred(OM_uint32 *minor_status,
+                 gss_cred_id_t *cred_handle)
+{
+    PP(">>>> Calling gss_release_cred...");
+    if (cred_handle && *cred_handle) {
+        if ((*cred_handle)->phCredK) {
+            FreeCredentialsHandle((*cred_handle)->phCredK);
+            delete (*cred_handle)->phCredK;
+        }
+        if ((*cred_handle)->phCredS) {
+            FreeCredentialsHandle((*cred_handle)->phCredS);
+            delete (*cred_handle)->phCredS;
+        }
+        delete *cred_handle;
+        *cred_handle = GSS_C_NO_CREDENTIAL;
+    }
+    return GSS_S_COMPLETE;
+}
+
+__declspec(dllexport) OM_uint32
+gss_inquire_cred(OM_uint32 *minor_status,
+                 gss_const_cred_id_t cred_handle,
+                 gss_name_t *name,
+                 OM_uint32 *lifetime,
+                 gss_cred_usage_t *cred_usage,
+                 gss_OID_set *mechanisms)
+{
+    PP(">>>> Calling gss_inquire_cred...");
+    CHECK_CRED(cred_handle)
+
+    CredHandle* cred = cred_handle->phCredK
+            ? cred_handle->phCredK
+            : cred_handle->phCredS;
+    SECURITY_STATUS ss;
+    if (name) {
+        *name = GSS_C_NO_NAME;
+        SecPkgCredentials_Names snames;
+        ss = QueryCredentialsAttributes(cred, SECPKG_CRED_ATTR_NAMES, &snames);
+        if (!SEC_SUCCESS(ss)) {
+            return GSS_S_FAILURE;
+        }
+        SEC_WCHAR* names = new SEC_WCHAR[lstrlen(snames.sUserName) + 1];
+        if (names == NULL) {
+            return GSS_S_FAILURE;
+        }
+        StringCchCopy(names, lstrlen(snames.sUserName) + 1, snames.sUserName);
+        FreeContextBuffer(snames.sUserName);
+        PP("Allocate new name at %p", names);
+        gss_name_t name1 = new gss_name_struct;
+        if (name1 == NULL) {
+            delete[] names;
+            return GSS_S_FAILURE;
+        }
+        name1->name = names;
+        *name = (gss_name_t) name1;
+    }
+    if (lifetime) {
+        *lifetime = cred_handle->time;
+    }
+    if (cred_usage) {
+        *cred_usage = 1; // We only support INITIATE_ONLY now
+    }
+    if (mechanisms) {
+        // Useless for Java
+    }
+    // Others inquiries not supported yet
+    return GSS_S_COMPLETE;
+}
+
+__declspec(dllexport) OM_uint32
+gss_import_sec_context(OM_uint32 *minor_status,
+                       const gss_buffer_t interprocess_token,
+                       gss_ctx_id_t *context_handle)
+{
+    // Not transferable, return FAILURE
+    PP(">>>> Calling UNIMPLEMENTED gss_import_sec_context...");
+    *minor_status = 0;
+    return GSS_S_FAILURE;
+}
+
+__declspec(dllexport) OM_uint32
+gss_init_sec_context(OM_uint32 *minor_status,
+                     gss_const_cred_id_t initiator_cred_handle,
+                     gss_ctx_id_t *context_handle,
+                     gss_const_name_t target_name,
+                     const gss_OID mech_type,
+                     OM_uint32 req_flags,
+                     OM_uint32 time_req,
+                     const gss_channel_bindings_t input_chan_bindings,
+                     const gss_buffer_t input_token,
+                     gss_OID *actual_mech_type,
+                     gss_buffer_t output_token,
+                     OM_uint32 *ret_flags,
+                     OM_uint32 *time_rec)
+{
+    PP(">>>> Calling gss_init_sec_context...");
+    CHECK_NAME(target_name)
+    CHECK_OUTPUT(output_token)
+
+    SECURITY_STATUS ss;
+    TimeStamp lifeTime;
+    SecBufferDesc inBuffDesc;
+    SecBuffer inSecBuff;
+    SecBufferDesc outBuffDesc;
+    SecBuffer outSecBuff;
+    BOOLEAN isSPNEGO = is_same_oid(mech_type, &SPNEGO_OID);
+
+    gss_ctx_id_t pc;
+
+    output_token->length = 0;
+    output_token->value = NULL;
+
+    BOOLEAN firstTime = (*context_handle == GSS_C_NO_CONTEXT);
+    PP("First time? %d", firstTime);
+    if (firstTime) {
+        pc = new_context(isSPNEGO);
+        if (pc == NULL) {
+            return GSS_S_FAILURE;
+        }
+        *context_handle = (gss_ctx_id_t) pc;
+    } else {
+        pc = *context_handle;
+    }
+
+    if (pc == NULL) {
+        return GSS_S_NO_CONTEXT;
+    }
+
+    DWORD outFlag;
+    TCHAR outName[100];
+
+    OM_uint32 minor;
+    gss_buffer_desc tn;
+    gss_display_name(&minor, target_name, &tn, NULL);
+    int len = MultiByteToWideChar(CP_UTF8, 0, (LPCCH)tn.value, (int)tn.length,
+            outName, sizeof(outName) - 1);
+    if (len == 0) {
+        goto err;
+    }
+    outName[len] = 0;
+
+    int flag = flag_gss_to_sspi(req_flags) | ISC_REQ_ALLOCATE_MEMORY;
+
+    outBuffDesc.ulVersion = SECBUFFER_VERSION;
+    outBuffDesc.cBuffers = 1;
+    outBuffDesc.pBuffers = &outSecBuff;
+
+    outSecBuff.BufferType = SECBUFFER_TOKEN;
+
+    if (!firstTime) {
+        inBuffDesc.ulVersion = SECBUFFER_VERSION;
+        inBuffDesc.cBuffers = 1;
+        inBuffDesc.pBuffers = &inSecBuff;
+
+        inSecBuff.BufferType = SECBUFFER_TOKEN;
+        inSecBuff.cbBuffer = (ULONG)input_token->length;
+        inSecBuff.pvBuffer = input_token->value;
+    } else if (!pc->phCred) {
+        if (isSPNEGO && initiator_cred_handle
+                && initiator_cred_handle->phCredS) {
+            PP("Find SPNEGO credentials");
+            pc->phCred = initiator_cred_handle->phCredS;
+            pc->isLocalCred = FALSE;
+        } else if (!isSPNEGO && initiator_cred_handle
+                && initiator_cred_handle->phCredK) {
+            PP("Find Kerberos credentials");
+            pc->phCred = initiator_cred_handle->phCredK;
+            pc->isLocalCred = FALSE;
+        } else {
+            PP("No credentials provided, acquire myself");
+            CredHandle* newCred = new CredHandle;
+            SEC_WINNT_AUTH_IDENTITY_EX auth;
+            ZeroMemory(&auth, sizeof(auth));
+            auth.Version = SEC_WINNT_AUTH_IDENTITY_VERSION;
+            auth.Length = sizeof(auth);
+            auth.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
+            auth.PackageList = (unsigned short*)L"Kerberos";
+            auth.PackageListLength = 8;
+            ss = AcquireCredentialsHandle(
+                    NULL,
+                    isSPNEGO ? L"Negotiate" : L"Kerberos",
+                    SECPKG_CRED_OUTBOUND,
+                    NULL,
+                    isSPNEGO ? &auth : NULL,
+                    NULL,
+                    NULL,
+                    newCred,
+                    &lifeTime);
+            if (!(SEC_SUCCESS(ss))) {
+                delete newCred;
+                goto err;
+            }
+            pc->phCred = newCred;
+            pc->isLocalCred = TRUE;
+        }
+    }
+    ss = InitializeSecurityContext(
+            pc->phCred,
+            firstTime ? NULL : &pc->hCtxt,
+            outName,
+            flag,
+            0,
+            SECURITY_NATIVE_DREP,
+            firstTime ? NULL : &inBuffDesc,
+            0,
+            &pc->hCtxt,
+            &outBuffDesc,
+            &outFlag,
+            &lifeTime);
+
+    if (!SEC_SUCCESS(ss)) {
+        // TODO: seems NativeGSSContext has not failed here.
+        PP("InitializeSecurityContext failed");
+        goto err;
+    }
+
+    pc->flags = *ret_flags = flag_sspi_to_gss(outFlag);
+
+    // Ignore the result of the next call. Might fail before context established.
+    QueryContextAttributes(
+            &pc->hCtxt, SECPKG_ATTR_SIZES, &pc->SecPkgContextSizes);
+    PP("cbMaxSignature: %ld. cbBlockSize: %ld. cbSecurityTrailer: %ld",
+            pc->SecPkgContextSizes.cbMaxSignature,
+            pc->SecPkgContextSizes.cbBlockSize,
+            pc->SecPkgContextSizes.cbSecurityTrailer);
+
+    output_token->length = outSecBuff.cbBuffer;
+    if (outSecBuff.cbBuffer) {
+        // No idea how user would free the data. Let's duplicate one.
+        output_token->value = new char[outSecBuff.cbBuffer];
+        if (!output_token->value) {
+            FreeContextBuffer(outSecBuff.pvBuffer);
+            output_token->length = 0;
+            goto err;
+        }
+        memcpy(output_token->value, outSecBuff.pvBuffer, outSecBuff.cbBuffer);
+        FreeContextBuffer(outSecBuff.pvBuffer);
+    }
+
+    if (ss == SEC_I_CONTINUE_NEEDED) {
+        return GSS_S_CONTINUE_NEEDED;
+    } else {
+        pc->established = true;
+        ss = QueryContextAttributes(&pc->hCtxt, SECPKG_ATTR_NATIVE_NAMES, &pc->nnames);
+        if (!SEC_SUCCESS(ss)) {
+            goto err;
+        }
+        PP("Names. %ls %ls", pc->nnames.sClientName, pc->nnames.sServerName);
+        *ret_flags |= GSS_C_PROT_READY_FLAG;
+        return GSS_S_COMPLETE;
+    }
+err:
+    if (firstTime) {
+        OM_uint32 dummy;
+        gss_delete_sec_context(&dummy, context_handle, GSS_C_NO_BUFFER);
+    }
+    if (output_token->value) {
+        gss_release_buffer(NULL, output_token);
+        output_token = GSS_C_NO_BUFFER;
+    }
+    return GSS_S_FAILURE;
+}
+
+__declspec(dllexport) OM_uint32
+gss_accept_sec_context(OM_uint32 *minor_status,
+                       gss_ctx_id_t *context_handle,
+                       gss_const_cred_id_t acceptor_cred_handle,
+                       const gss_buffer_t input_token,
+                       const gss_channel_bindings_t input_chan_bindings,
+                       gss_name_t *src_name,
+                       gss_OID *mech_type,
+                       gss_buffer_t output_token,
+                       OM_uint32 *ret_flags,
+                       OM_uint32 *time_rec,
+                       gss_cred_id_t *delegated_cred_handle)
+{
+    PP(">>>> Calling UNIMPLEMENTED gss_accept_sec_context...");
+    PP("gss_accept_sec_context is not supported in this initiator-only library");
+    return GSS_S_FAILURE;
+}
+
+__declspec(dllexport) OM_uint32
+gss_inquire_context(OM_uint32 *minor_status,
+                    gss_const_ctx_id_t context_handle,
+                    gss_name_t *src_name,
+                    gss_name_t *targ_name,
+                    OM_uint32 *lifetime_rec,
+                    gss_OID *mech_type,
+                    OM_uint32 *ctx_flags,
+                    int *locally_initiated,
+                    int *open)
+{
+    PP(">>>> Calling gss_inquire_context...");
+    CHECK_CONTEXT(context_handle)
+
+    gss_name_t n1 = NULL;
+    gss_name_t n2 = NULL;
+    if (!context_handle->established) {
+        return GSS_S_NO_CONTEXT;
+    }
+    if (src_name != NULL) {
+        n1 = new gss_name_struct;
+        if (n1 == NULL) {
+            goto err;
+        }
+        n1->name = new SEC_WCHAR[lstrlen(context_handle->nnames.sClientName) + 1];
+        if (n1->name == NULL) {
+            goto err;
+        }
+        PP("Allocate new name at %p", n1->name);
+        StringCchCopy(n1->name, lstrlen(context_handle->nnames.sClientName) + 1,
+                context_handle->nnames.sClientName);
+        *src_name = (gss_name_t) n1;
+    }
+    if (targ_name != NULL) {
+        n2 = new gss_name_struct;
+        if (n2 == NULL) {
+            goto err;
+        }
+        n2->name = new SEC_WCHAR[lstrlen(context_handle->nnames.sServerName) + 1];
+        if (n2->name == NULL) {
+            goto err;
+        }
+        PP("Allocate new name at %p", n2->name);
+        StringCchCopy(n2->name, lstrlen(context_handle->nnames.sServerName) + 1,
+                context_handle->nnames.sServerName);
+        *targ_name = (gss_name_t) n2;
+    }
+    if (lifetime_rec != NULL) {
+        SecPkgContext_Lifespan ls;
+        SECURITY_STATUS ss;
+        ss = QueryContextAttributes(
+                (PCtxtHandle)&context_handle->hCtxt,
+                SECPKG_ATTR_LIFESPAN,
+                &ls);
+        if (!SEC_SUCCESS(ss)) {
+            goto err;
+        }
+        *lifetime_rec = seconds_until(0, &ls.tsExpiry);
+    }
+    if (mech_type != NULL) {
+        *mech_type = context_handle->isSPNEGO
+                ? &SPNEGO_OID : &KRB5_OID;
+    }
+    if (ctx_flags != NULL) {
+        *ctx_flags = context_handle->flags;
+    }
+    if (locally_initiated != NULL) {
+        // We are always initiator
+        *locally_initiated = 1;
+    }
+    return GSS_S_COMPLETE;
+err:
+    if (n1 != NULL) {
+        if (n1->name != NULL) {
+            delete[] n1->name;
+        }
+        delete n1;
+        n1 = NULL;
+    }
+    if (n2 != NULL) {
+        if (n2->name != NULL) {
+            delete[] n2->name;
+        }
+        delete n2;
+        n2 = NULL;
+    }
+    return GSS_S_FAILURE;
+}
+
+__declspec(dllexport) OM_uint32
+gss_delete_sec_context(OM_uint32 *minor_status,
+                       gss_ctx_id_t *context_handle,
+                       gss_buffer_t output_token)
+{
+    PP(">>>> Calling gss_delete_sec_context...");
+    CHECK_CONTEXT(context_handle)
+
+    DeleteSecurityContext(&(*context_handle)->hCtxt);
+    if ((*context_handle)->isLocalCred && (*context_handle)->phCred != NULL) {
+        FreeCredentialsHandle((*context_handle)->phCred);
+        (*context_handle)->phCred = NULL;
+    }
+    if ((*context_handle)->nnames.sClientName != NULL) {
+        FreeContextBuffer((*context_handle)->nnames.sClientName);
+        (*context_handle)->nnames.sClientName = NULL;
+    }
+    if ((*context_handle)->nnames.sServerName != NULL) {
+        FreeContextBuffer((*context_handle)->nnames.sServerName);
+        (*context_handle)->nnames.sServerName = NULL;
+    }
+    delete (*context_handle);
+    *context_handle = GSS_C_NO_CONTEXT;
+    return GSS_S_COMPLETE;
+}
+
+__declspec(dllexport) OM_uint32
+gss_context_time(OM_uint32 *minor_status,
+                 gss_const_ctx_id_t context_handle,
+                 OM_uint32 *time_rec)
+{
+    PP(">>>> Calling IMPLEMENTED gss_context_time...");
+    CHECK_CONTEXT(context_handle)
+    CHECK_OUTPUT(time_rec)
+
+    SECURITY_STATUS ss;
+    SecPkgContext_Lifespan ls;
+    ss = QueryContextAttributes(
+            (PCtxtHandle)&context_handle->hCtxt,
+            SECPKG_ATTR_LIFESPAN,
+            &ls);
+    if (ss == SEC_E_OK) {
+        *time_rec = seconds_until(0, &ls.tsExpiry);
+        show_time("context start", &ls.tsStart);
+        show_time("context expiry", &ls.tsExpiry);
+        return *time_rec == 0 ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE;
+    } else {
+        return GSS_S_FAILURE;
+    }
+}
+
+__declspec(dllexport) OM_uint32
+gss_wrap_size_limit(OM_uint32 *minor_status,
+                    gss_const_ctx_id_t context_handle,
+                    int conf_req_flag,
+                    gss_qop_t qop_req,
+                    OM_uint32 req_output_size,
+                    OM_uint32 *max_input_size)
+{
+    PP(">>>> Calling gss_wrap_size_limit...");
+    CHECK_CONTEXT(context_handle)
+    CHECK_OUTPUT(max_input_size)
+
+    *max_input_size = req_output_size
+            - context_handle->SecPkgContextSizes.cbSecurityTrailer
+            - context_handle->SecPkgContextSizes.cbBlockSize;
+    return GSS_S_COMPLETE;
+}
+
+__declspec(dllexport) OM_uint32
+gss_export_sec_context(OM_uint32 *minor_status,
+                       gss_ctx_id_t *context_handle,
+                       gss_buffer_t interprocess_token)
+{
+    PP(">>>> Calling UNIMPLEMENTED gss_export_sec_context...");
+    return GSS_S_FAILURE;
+}
+
+__declspec(dllexport) OM_uint32
+gss_get_mic(OM_uint32 *minor_status,
+            gss_const_ctx_id_t context_handle,
+            gss_qop_t qop_req,
+            const gss_buffer_t message_buffer,
+            gss_buffer_t msg_token)
+{
+    PP(">>>> Calling gss_get_mic...");
+    CHECK_CONTEXT(context_handle);
+    CHECK_BUFFER(message_buffer);
+    CHECK_OUTPUT(msg_token);
+
+    SECURITY_STATUS ss;
+    SecBufferDesc buffDesc;
+    SecBuffer secBuff[2];
+
+    buffDesc.cBuffers = 2;
+    buffDesc.pBuffers = secBuff;
+    buffDesc.ulVersion = SECBUFFER_VERSION;
+
+    secBuff[0].BufferType = SECBUFFER_DATA;
+    secBuff[0].cbBuffer = (ULONG)message_buffer->length;
+    secBuff[0].pvBuffer = message_buffer->value;
+
+    secBuff[1].BufferType = SECBUFFER_TOKEN;
+    secBuff[1].cbBuffer = context_handle->SecPkgContextSizes.cbMaxSignature;
+    secBuff[1].pvBuffer = msg_token->value = new char[secBuff[1].cbBuffer];
+
+    ss = MakeSignature((PCtxtHandle)&context_handle->hCtxt, 0, &buffDesc, 0);
+
+    if (!SEC_SUCCESS(ss)) {
+        msg_token->length = 0;
+        msg_token->value = NULL;
+        delete[] secBuff[1].pvBuffer;
+        return GSS_S_FAILURE;
+    }
+
+    msg_token->length = secBuff[1].cbBuffer;
+    return GSS_S_COMPLETE;
+}
+
+__declspec(dllexport) OM_uint32
+gss_verify_mic(OM_uint32 *minor_status,
+               gss_const_ctx_id_t context_handle,
+               const gss_buffer_t message_buffer,
+               const gss_buffer_t token_buffer,
+               gss_qop_t *qop_state)
+{
+    PP(">>>> Calling gss_verify_mic...");
+    CHECK_CONTEXT(context_handle);
+    CHECK_BUFFER(message_buffer);
+    CHECK_BUFFER(token_buffer);
+
+    SECURITY_STATUS ss;
+    SecBufferDesc buffDesc;
+    SecBuffer secBuff[2];
+    ULONG qop;
+
+    buffDesc.ulVersion = SECBUFFER_VERSION;
+    buffDesc.cBuffers = 2;
+    buffDesc.pBuffers = secBuff;
+
+    secBuff[0].BufferType = SECBUFFER_TOKEN;
+    secBuff[0].cbBuffer = (ULONG)token_buffer->length;
+    secBuff[0].pvBuffer = token_buffer->value;
+
+    secBuff[1].BufferType = SECBUFFER_DATA;
+    secBuff[1].cbBuffer = (ULONG)message_buffer->length;
+    secBuff[1].pvBuffer = message_buffer->value;
+
+    ss = VerifySignature((PCtxtHandle)&context_handle->hCtxt, &buffDesc, 0, &qop);
+    if (qop_state) {
+        *qop_state = qop;
+    }
+
+    if (ss == SEC_E_OK) {
+        return GSS_S_COMPLETE;
+    } else if (ss == SEC_E_OUT_OF_SEQUENCE) {
+        return GSS_S_UNSEQ_TOKEN;
+    } else {
+        return GSS_S_BAD_SIG;
+    }
+}
+
+__declspec(dllexport) OM_uint32
+gss_wrap(OM_uint32 *minor_status,
+         gss_const_ctx_id_t context_handle,
+         int conf_req_flag,
+         gss_qop_t qop_req,
+         const gss_buffer_t input_message_buffer,
+         int *conf_state,
+         gss_buffer_t output_message_buffer)
+{
+    PP(">>>> Calling gss_wrap...");
+    CHECK_CONTEXT(context_handle);
+    CHECK_BUFFER(input_message_buffer);
+    CHECK_OUTPUT(output_message_buffer);
+
+    SECURITY_STATUS ss;
+    SecBufferDesc buffDesc;
+    SecBuffer secBuff[3];
+
+    buffDesc.ulVersion = SECBUFFER_VERSION;
+    buffDesc.cBuffers = 3;
+    buffDesc.pBuffers = secBuff;
+
+    secBuff[0].BufferType = SECBUFFER_TOKEN;
+    secBuff[0].cbBuffer = context_handle->SecPkgContextSizes.cbSecurityTrailer;
+    output_message_buffer->value = secBuff[0].pvBuffer = malloc(
+            context_handle->SecPkgContextSizes.cbSecurityTrailer
+                    + input_message_buffer->length
+                    + context_handle->SecPkgContextSizes.cbBlockSize);;
+
+    secBuff[1].BufferType = SECBUFFER_DATA;
+    secBuff[1].cbBuffer = (ULONG)input_message_buffer->length;
+    secBuff[1].pvBuffer = malloc(secBuff[1].cbBuffer);
+    memcpy_s(secBuff[1].pvBuffer, secBuff[1].cbBuffer,
+            input_message_buffer->value, input_message_buffer->length);
+
+    secBuff[2].BufferType = SECBUFFER_PADDING;
+    secBuff[2].cbBuffer = context_handle->SecPkgContextSizes.cbBlockSize;
+    secBuff[2].pvBuffer = malloc(secBuff[2].cbBuffer);
+
+    ss = EncryptMessage((PCtxtHandle)&context_handle->hCtxt,
+            conf_req_flag ? 0 : SECQOP_WRAP_NO_ENCRYPT,
+            &buffDesc, 0);
+    if (conf_state) {
+        *conf_state = conf_req_flag;
+    }
+
+    if (!SEC_SUCCESS(ss)) {
+        free(secBuff[0].pvBuffer);
+        free(secBuff[1].pvBuffer);
+        free(secBuff[2].pvBuffer);
+        output_message_buffer->length = 0;
+        output_message_buffer->value = NULL;
+        return GSS_S_FAILURE;
+    }
+
+    memcpy_s((PBYTE)secBuff[0].pvBuffer + secBuff[0].cbBuffer,
+            input_message_buffer->length + context_handle->SecPkgContextSizes.cbBlockSize,
+            secBuff[1].pvBuffer,
+            secBuff[1].cbBuffer);
+    memcpy_s((PBYTE)secBuff[0].pvBuffer + secBuff[0].cbBuffer + secBuff[1].cbBuffer,
+            context_handle->SecPkgContextSizes.cbBlockSize,
+            secBuff[2].pvBuffer,
+            secBuff[2].cbBuffer);
+
+    output_message_buffer->length = secBuff[0].cbBuffer + secBuff[1].cbBuffer
+            + secBuff[2].cbBuffer;
+    free(secBuff[1].pvBuffer);
+    free(secBuff[2].pvBuffer);
+
+    return GSS_S_COMPLETE;
+}
+
+__declspec(dllexport) OM_uint32
+gss_unwrap(OM_uint32 *minor_status,
+           gss_const_ctx_id_t context_handle,
+           const gss_buffer_t input_message_buffer,
+           gss_buffer_t output_message_buffer,
+           int *conf_state,
+           gss_qop_t *qop_state)
+{
+    PP(">>>> Calling gss_unwrap...");
+    CHECK_CONTEXT(context_handle);
+    CHECK_BUFFER(input_message_buffer);
+    CHECK_OUTPUT(output_message_buffer);
+
+    SECURITY_STATUS ss;
+    SecBufferDesc buffDesc;
+    SecBuffer secBuff[2];
+    ULONG ulQop = 0;
+
+    buffDesc.cBuffers = 2;
+    buffDesc.pBuffers = secBuff;
+    buffDesc.ulVersion = SECBUFFER_VERSION;
+
+    secBuff[0].BufferType = SECBUFFER_STREAM;
+    secBuff[0].cbBuffer = (ULONG)input_message_buffer->length;
+    secBuff[0].pvBuffer = malloc(input_message_buffer->length);
+    memcpy_s(secBuff[0].pvBuffer, input_message_buffer->length,
+            input_message_buffer->value, input_message_buffer->length);
+
+    secBuff[1].BufferType = SECBUFFER_DATA;
+    secBuff[1].cbBuffer = 0;
+    secBuff[1].pvBuffer = NULL;
+
+    ss = DecryptMessage((PCtxtHandle)&context_handle->hCtxt, &buffDesc, 0, &ulQop);
+    if (qop_state) {
+        *qop_state = ulQop;
+    }
+    if (!SEC_SUCCESS(ss)) {
+        free(secBuff[0].pvBuffer);
+        output_message_buffer->length = 0;
+        output_message_buffer->value = NULL;
+        return GSS_S_FAILURE;
+    }
+
+    // Must allocate a new memory block so client can release it correctly
+    output_message_buffer->length = secBuff[1].cbBuffer;
+    output_message_buffer->value = new char[secBuff[1].cbBuffer];
+    memcpy_s(output_message_buffer->value, secBuff[1].cbBuffer,
+            secBuff[1].pvBuffer, secBuff[1].cbBuffer);
+    *conf_state = ulQop == SECQOP_WRAP_NO_ENCRYPT ? 0 : 1;
+
+    free(secBuff[0].pvBuffer);
+    return GSS_S_COMPLETE;
+}
+
+__declspec(dllexport) OM_uint32
+gss_indicate_mechs(OM_uint32 *minor_status,
+                   gss_OID_set *mech_set)
+{
+    PP(">>>> Calling gss_indicate_mechs...");
+    OM_uint32 major = GSS_S_COMPLETE;
+
+    ULONG ccPackages;
+    PSecPkgInfo packages;
+    EnumerateSecurityPackages(&ccPackages, &packages);
+    PP("EnumerateSecurityPackages returns %ld", ccPackages);
+    for (unsigned int i = 0; i < ccPackages; i++) {
+        PP("#%d: %ls, %ls\n", i, packages[i].Name, packages[i].Comment);
+    }
+    FreeContextBuffer(packages);
+
+    // Hardcode kerberos and SPNEGO support
+    major = gss_create_empty_oid_set(minor_status, mech_set);
+    if (major != GSS_S_COMPLETE) {
+        goto done;
+    }
+
+    major = gss_add_oid_set_member(minor_status, &KRB5_OID, mech_set);
+    if (major != GSS_S_COMPLETE) {
+        goto done;
+    }
+
+    major = gss_add_oid_set_member(minor_status, &SPNEGO_OID, mech_set);
+    if (major != GSS_S_COMPLETE) {
+        goto done;
+    }
+
+done:
+
+    if (major != GSS_S_COMPLETE) {
+        gss_release_oid_set(minor_status, mech_set);
+    }
+
+    return major;
+}
+
+__declspec(dllexport) OM_uint32
+gss_inquire_names_for_mech(OM_uint32 *minor_status,
+                           const gss_OID mechanism,
+                           gss_OID_set *name_types)
+{
+    PP(">>>> Calling gss_inquire_names_for_mech...");
+    CHECK_OID(mechanism);
+
+    if (gss_create_empty_oid_set(minor_status, name_types)) {
+        return GSS_S_FAILURE;
+    }
+    if (gss_add_oid_set_member(minor_status, &USER_NAME_OID, name_types)) {
+        goto err;
+    }
+    if (gss_add_oid_set_member(minor_status, &HOST_SERVICE_NAME_OID, name_types)) {
+        goto err;
+    }
+    if (!is_same_oid(mechanism, &SPNEGO_OID)) {
+        if (gss_add_oid_set_member(minor_status, &EXPORT_NAME_OID, name_types)) {
+            goto err;
+        }
+    }
+    return GSS_S_COMPLETE;
+err:
+    gss_release_oid_set(minor_status, name_types);
+    return GSS_S_FAILURE;
+}
+
+__declspec(dllexport) OM_uint32
+gss_add_oid_set_member(OM_uint32 *minor_status,
+                       const gss_OID member_oid,
+                       gss_OID_set *oid_set)
+{
+    PP(">>>> Calling gss_add_oid_set_member...");
+    CHECK_OID(member_oid);
+    CHECK_OUTPUT(oid_set);
+
+
+    int count = (int)(*oid_set)->count;
+    for (int i = 0; i < count; i++) {
+        if (is_same_oid(&(*oid_set)->elements[i], member_oid)) {
+            // already there
+            return GSS_S_COMPLETE;
+        }
+    }
+    gss_OID existing = (*oid_set)->elements;
+    gss_OID newcopy = new gss_OID_desc[count + 1];
+    if (newcopy == NULL) {
+        return GSS_S_FAILURE;
+    }
+    if (existing) {
+        memcpy_s(newcopy, (count + 1) * sizeof(gss_OID_desc),
+                existing, count * sizeof(gss_OID_desc));
+    }
+    newcopy[count].length = member_oid->length;
+    newcopy[count].elements = new char[member_oid->length];
+    if (newcopy[count].elements == NULL) {
+        delete[] newcopy;
+        return GSS_S_FAILURE;
+    }
+    memcpy_s(newcopy[count].elements, member_oid->length,
+            member_oid->elements, member_oid->length);
+    (*oid_set)->elements = newcopy;
+    (*oid_set)->count++;
+    if (existing) {
+        delete[] existing;
+    }
+
+    return GSS_S_COMPLETE;
+}
+
+__declspec(dllexport) OM_uint32
+gss_display_status(OM_uint32 *minor_status,
+                   OM_uint32 status_value,
+                   int status_type,
+                   const gss_OID mech_type,
+                   OM_uint32 *message_context,
+                   gss_buffer_t status_string)
+{
+    PP(">>>> Calling gss_display_status...");
+    TCHAR msg[256];
+    int len = FormatMessage(
+            FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+            0, status_value,
+            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+            msg, 256, 0);
+    if (len > 0) {
+        status_string->value = new char[len + 20];
+        status_string->length = sprintf_s(
+                (LPSTR)status_string->value, len + 19,
+                "(%lx) %ls", status_value, msg);
+    } else {
+        status_string->value = new char[33];
+        status_string->length = sprintf_s(
+                (LPSTR)status_string->value, 32,
+                "status is %lx", status_value);
+    }
+    if (status_string->length <= 0) {
+        gss_release_buffer(NULL, status_string);
+        status_string = GSS_C_NO_BUFFER;
+        return GSS_S_FAILURE;
+    } else {
+        return GSS_S_COMPLETE;
+    }
+}
+
+__declspec(dllexport) OM_uint32
+gss_create_empty_oid_set(OM_uint32 *minor_status,
+                         gss_OID_set *oid_set)
+{
+    PP(">>>> Calling gss_create_empty_oid_set...");
+    CHECK_OUTPUT(oid_set);
+
+    if (*oid_set = new gss_OID_set_desc) {
+        memset(*oid_set, 0, sizeof(gss_OID_set_desc));
+        return GSS_S_COMPLETE;
+    }
+    return GSS_S_FAILURE;
+}
+
+__declspec(dllexport) OM_uint32
+gss_release_oid_set(OM_uint32 *minor_status,
+                    gss_OID_set *set)
+{
+    PP(">>>> Calling gss_release_oid_set...");
+    if (set == NULL || *set == GSS_C_NO_OID_SET) {
+        return GSS_S_COMPLETE;
+    }
+    for (int i = 0; i < (*set)->count; i++) {
+        delete[] (*set)->elements[i].elements;
+    }
+    delete[] (*set)->elements;
+    delete *set;
+    *set = GSS_C_NO_OID_SET;
+    return GSS_S_COMPLETE;
+}
+
+__declspec(dllexport) OM_uint32
+gss_release_buffer(OM_uint32 *minor_status,
+                   gss_buffer_t buffer)
+{
+    PP(">>>> Calling gss_release_buffer...");
+    if (buffer == NULL || buffer == GSS_C_NO_BUFFER) {
+        return GSS_S_COMPLETE;
+    }
+    if (buffer->value) {
+        delete[] buffer->value;
+        buffer->value = NULL;
+    }
+    buffer->length = 0;
+    return GSS_S_COMPLETE;
+}
+
+/* End implemented section */
+
+#ifdef __cplusplus
+}
+#endif
--- a/src/jdk.compiler/share/classes/com/sun/tools/doclint/Entity.java	Wed Jun 12 10:02:49 2019 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/doclint/Entity.java	Thu Jun 13 11:31:36 2019 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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,305 +26,2163 @@
 package com.sun.tools.doclint;
 
 import java.util.HashMap;
-import java.util.Map;
 
 /**
- * Table of entities defined in HTML 4.01.
+ * Table of entities defined in HTML 5.2.
  *
- * <p> Derived from
- * <a href="http://www.w3.org/TR/html4/sgml/entities.html">Character entity references in HTML 4</a>.
- *
- * The name of the member follows the name of the entity,
- * except when it clashes with a keyword, in which case
- * it is prefixed by '_'.
+ * <p> Derived from the
+ * <a href="https://www.w3.org/TR/html52/syntax.html#named-character-references">Named character references</a>
+ * section of the HTML 5.2 specification.
  *
  * <p><b>This is NOT part of any supported API.
  * If you write code that depends on this, you do so at your own
  * risk.  This code and its internal interfaces are subject to change
  * or deletion without notice.</b></p>
  */
-public enum Entity {
-    nbsp(160),
-    iexcl(161),
-    cent(162),
-    pound(163),
-    curren(164),
-    yen(165),
-    brvbar(166),
-    sect(167),
-    uml(168),
-    copy(169),
-    ordf(170),
-    laquo(171),
-    not(172),
-    shy(173),
-    reg(174),
-    macr(175),
-    deg(176),
-    plusmn(177),
-    sup2(178),
-    sup3(179),
-    acute(180),
-    micro(181),
-    para(182),
-    middot(183),
-    cedil(184),
-    sup1(185),
-    ordm(186),
-    raquo(187),
-    frac14(188),
-    frac12(189),
-    frac34(190),
-    iquest(191),
-    Agrave(192),
-    Aacute(193),
-    Acirc(194),
-    Atilde(195),
-    Auml(196),
-    Aring(197),
-    AElig(198),
-    Ccedil(199),
-    Egrave(200),
-    Eacute(201),
-    Ecirc(202),
-    Euml(203),
-    Igrave(204),
-    Iacute(205),
-    Icirc(206),
-    Iuml(207),
-    ETH(208),
-    Ntilde(209),
-    Ograve(210),
-    Oacute(211),
-    Ocirc(212),
-    Otilde(213),
-    Ouml(214),
-    times(215),
-    Oslash(216),
-    Ugrave(217),
-    Uacute(218),
-    Ucirc(219),
-    Uuml(220),
-    Yacute(221),
-    THORN(222),
-    szlig(223),
-    agrave(224),
-    aacute(225),
-    acirc(226),
-    atilde(227),
-    auml(228),
-    aring(229),
-    aelig(230),
-    ccedil(231),
-    egrave(232),
-    eacute(233),
-    ecirc(234),
-    euml(235),
-    igrave(236),
-    iacute(237),
-    icirc(238),
-    iuml(239),
-    eth(240),
-    ntilde(241),
-    ograve(242),
-    oacute(243),
-    ocirc(244),
-    otilde(245),
-    ouml(246),
-    divide(247),
-    oslash(248),
-    ugrave(249),
-    uacute(250),
-    ucirc(251),
-    uuml(252),
-    yacute(253),
-    thorn(254),
-    yuml(255),
-    fnof(402),
-    Alpha(913),
-    Beta(914),
-    Gamma(915),
-    Delta(916),
-    Epsilon(917),
-    Zeta(918),
-    Eta(919),
-    Theta(920),
-    Iota(921),
-    Kappa(922),
-    Lambda(923),
-    Mu(924),
-    Nu(925),
-    Xi(926),
-    Omicron(927),
-    Pi(928),
-    Rho(929),
-    Sigma(931),
-    Tau(932),
-    Upsilon(933),
-    Phi(934),
-    Chi(935),
-    Psi(936),
-    Omega(937),
-    alpha(945),
-    beta(946),
-    gamma(947),
-    delta(948),
-    epsilon(949),
-    zeta(950),
-    eta(951),
-    theta(952),
-    iota(953),
-    kappa(954),
-    lambda(955),
-    mu(956),
-    nu(957),
-    xi(958),
-    omicron(959),
-    pi(960),
-    rho(961),
-    sigmaf(962),
-    sigma(963),
-    tau(964),
-    upsilon(965),
-    phi(966),
-    chi(967),
-    psi(968),
-    omega(969),
-    thetasym(977),
-    upsih(978),
-    piv(982),
-    bull(8226),
-    hellip(8230),
-    prime(8242),
-    Prime(8243),
-    oline(8254),
-    frasl(8260),
-    weierp(8472),
-    image(8465),
-    real(8476),
-    trade(8482),
-    alefsym(8501),
-    larr(8592),
-    uarr(8593),
-    rarr(8594),
-    darr(8595),
-    harr(8596),
-    crarr(8629),
-    lArr(8656),
-    uArr(8657),
-    rArr(8658),
-    dArr(8659),
-    hArr(8660),
-    forall(8704),
-    part(8706),
-    exist(8707),
-    empty(8709),
-    nabla(8711),
-    isin(8712),
-    notin(8713),
-    ni(8715),
-    prod(8719),
-    sum(8721),
-    minus(8722),
-    lowast(8727),
-    radic(8730),
-    prop(8733),
-    infin(8734),
-    ang(8736),
-    and(8743),
-    or(8744),
-    cap(8745),
-    cup(8746),
-    _int(8747),
-    there4(8756),
-    sim(8764),
-    cong(8773),
-    asymp(8776),
-    ne(8800),
-    equiv(8801),
-    le(8804),
-    ge(8805),
-    sub(8834),
-    sup(8835),
-    nsub(8836),
-    sube(8838),
-    supe(8839),
-    oplus(8853),
-    otimes(8855),
-    perp(8869),
-    sdot(8901),
-    lceil(8968),
-    rceil(8969),
-    lfloor(8970),
-    rfloor(8971),
-    lang(9001),
-    rang(9002),
-    loz(9674),
-    spades(9824),
-    clubs(9827),
-    hearts(9829),
-    diams(9830),
-    quot(34),
-    amp(38),
-    lt(60),
-    gt(62),
-    OElig(338),
-    oelig(339),
-    Scaron(352),
-    scaron(353),
-    Yuml(376),
-    circ(710),
-    tilde(732),
-    ensp(8194),
-    emsp(8195),
-    thinsp(8201),
-    zwnj(8204),
-    zwj(8205),
-    lrm(8206),
-    rlm(8207),
-    ndash(8211),
-    mdash(8212),
-    lsquo(8216),
-    rsquo(8217),
-    sbquo(8218),
-    ldquo(8220),
-    rdquo(8221),
-    bdquo(8222),
-    dagger(8224),
-    Dagger(8225),
-    permil(8240),
-    lsaquo(8249),
-    rsaquo(8250),
-    euro(8364);
+public class Entity {
 
-    public final int code;
+    private static final HashMap<String,String> html5Entities = new HashMap<>();
 
-    private Entity(int code) {
-        this.code = code;
+    static {
+        html5Entities.put("Aacute", "\u00C1");
+        html5Entities.put("aacute", "\u00E1");
+        html5Entities.put("Abreve", "\u0102");
+        html5Entities.put("abreve", "\u0103");
+        html5Entities.put("ac", "\u223E");
+        html5Entities.put("acd", "\u223F");
+        html5Entities.put("acE", "\u223E\u0333");
+        html5Entities.put("Acirc", "\u00C2");
+        html5Entities.put("acirc", "\u00E2");
+        html5Entities.put("acute", "\u00B4");
+        html5Entities.put("Acy", "\u0410");
+        html5Entities.put("acy", "\u0430");
+        html5Entities.put("AElig", "\u00C6");
+        html5Entities.put("aelig", "\u00E6");
+        html5Entities.put("af", "\u2061");
+        html5Entities.put("Afr", "\uD835\uDD04");
+        html5Entities.put("afr", "\uD835\uDD1E");
+        html5Entities.put("Agrave", "\u00C0");
+        html5Entities.put("agrave", "\u00E0");
+        html5Entities.put("alefsym", "\u2135");
+        html5Entities.put("aleph", "\u2135");
+        html5Entities.put("Alpha", "\u0391");
+        html5Entities.put("alpha", "\u03B1");
+        html5Entities.put("Amacr", "\u0100");
+        html5Entities.put("amacr", "\u0101");
+        html5Entities.put("amalg", "\u2A3F");
+        html5Entities.put("amp", "\u0026");
+        html5Entities.put("AMP", "\u0026");
+        html5Entities.put("andand", "\u2A55");
+        html5Entities.put("And", "\u2A53");
+        html5Entities.put("and", "\u2227");
+        html5Entities.put("andd", "\u2A5C");
+        html5Entities.put("andslope", "\u2A58");
+        html5Entities.put("andv", "\u2A5A");
+        html5Entities.put("ang", "\u2220");
+        html5Entities.put("ange", "\u29A4");
+        html5Entities.put("angle", "\u2220");
+        html5Entities.put("angmsdaa", "\u29A8");
+        html5Entities.put("angmsdab", "\u29A9");
+        html5Entities.put("angmsdac", "\u29AA");
+        html5Entities.put("angmsdad", "\u29AB");
+        html5Entities.put("angmsdae", "\u29AC");
+        html5Entities.put("angmsdaf", "\u29AD");
+        html5Entities.put("angmsdag", "\u29AE");
+        html5Entities.put("angmsdah", "\u29AF");
+        html5Entities.put("angmsd", "\u2221");
+        html5Entities.put("angrt", "\u221F");
+        html5Entities.put("angrtvb", "\u22BE");
+        html5Entities.put("angrtvbd", "\u299D");
+        html5Entities.put("angsph", "\u2222");
+        html5Entities.put("angst", "\u00C5");
+        html5Entities.put("angzarr", "\u237C");
+        html5Entities.put("Aogon", "\u0104");
+        html5Entities.put("aogon", "\u0105");
+        html5Entities.put("Aopf", "\uD835\uDD38");
+        html5Entities.put("aopf", "\uD835\uDD52");
+        html5Entities.put("apacir", "\u2A6F");
+        html5Entities.put("ap", "\u2248");
+        html5Entities.put("apE", "\u2A70");
+        html5Entities.put("ape", "\u224A");
+        html5Entities.put("apid", "\u224B");
+        html5Entities.put("apos", "\u0027");
+        html5Entities.put("ApplyFunction", "\u2061");
+        html5Entities.put("approx", "\u2248");
+        html5Entities.put("approxeq", "\u224A");
+        html5Entities.put("Aring", "\u00C5");
+        html5Entities.put("aring", "\u00E5");
+        html5Entities.put("Ascr", "\uD835\uDC9C");
+        html5Entities.put("ascr", "\uD835\uDCB6");
+        html5Entities.put("Assign", "\u2254");
+        html5Entities.put("ast", "\u002A");
+        html5Entities.put("asymp", "\u2248");
+        html5Entities.put("asympeq", "\u224D");
+        html5Entities.put("Atilde", "\u00C3");
+        html5Entities.put("atilde", "\u00E3");
+        html5Entities.put("Auml", "\u00C4");
+        html5Entities.put("auml", "\u00E4");
+        html5Entities.put("awconint", "\u2233");
+        html5Entities.put("awint", "\u2A11");
+        html5Entities.put("backcong", "\u224C");
+        html5Entities.put("backepsilon", "\u03F6");
+        html5Entities.put("backprime", "\u2035");
+        html5Entities.put("backsim", "\u223D");
+        html5Entities.put("backsimeq", "\u22CD");
+        html5Entities.put("Backslash", "\u2216");
+        html5Entities.put("Barv", "\u2AE7");
+        html5Entities.put("barvee", "\u22BD");
+        html5Entities.put("barwed", "\u2305");
+        html5Entities.put("Barwed", "\u2306");
+        html5Entities.put("barwedge", "\u2305");
+        html5Entities.put("bbrk", "\u23B5");
+        html5Entities.put("bbrktbrk", "\u23B6");
+        html5Entities.put("bcong", "\u224C");
+        html5Entities.put("Bcy", "\u0411");
+        html5Entities.put("bcy", "\u0431");
+        html5Entities.put("bdquo", "\u201E");
+        html5Entities.put("becaus", "\u2235");
+        html5Entities.put("because", "\u2235");
+        html5Entities.put("Because", "\u2235");
+        html5Entities.put("bemptyv", "\u29B0");
+        html5Entities.put("bepsi", "\u03F6");
+        html5Entities.put("bernou", "\u212C");
+        html5Entities.put("Bernoullis", "\u212C");
+        html5Entities.put("Beta", "\u0392");
+        html5Entities.put("beta", "\u03B2");
+        html5Entities.put("beth", "\u2136");
+        html5Entities.put("between", "\u226C");
+        html5Entities.put("Bfr", "\uD835\uDD05");
+        html5Entities.put("bfr", "\uD835\uDD1F");
+        html5Entities.put("bigcap", "\u22C2");
+        html5Entities.put("bigcirc", "\u25EF");
+        html5Entities.put("bigcup", "\u22C3");
+        html5Entities.put("bigodot", "\u2A00");
+        html5Entities.put("bigoplus", "\u2A01");
+        html5Entities.put("bigotimes", "\u2A02");
+        html5Entities.put("bigsqcup", "\u2A06");
+        html5Entities.put("bigstar", "\u2605");
+        html5Entities.put("bigtriangledown", "\u25BD");
+        html5Entities.put("bigtriangleup", "\u25B3");
+        html5Entities.put("biguplus", "\u2A04");
+        html5Entities.put("bigvee", "\u22C1");
+        html5Entities.put("bigwedge", "\u22C0");
+        html5Entities.put("bkarow", "\u290D");
+        html5Entities.put("blacklozenge", "\u29EB");
+        html5Entities.put("blacksquare", "\u25AA");
+        html5Entities.put("blacktriangle", "\u25B4");
+        html5Entities.put("blacktriangledown", "\u25BE");
+        html5Entities.put("blacktriangleleft", "\u25C2");
+        html5Entities.put("blacktriangleright", "\u25B8");
+        html5Entities.put("blank", "\u2423");
+        html5Entities.put("blk12", "\u2592");
+        html5Entities.put("blk14", "\u2591");
+        html5Entities.put("blk34", "\u2593");
+        html5Entities.put("block", "\u2588");
+        html5Entities.put("bne", "\u003D\u20E5");
+        html5Entities.put("bnequiv", "\u2261\u20E5");
+        html5Entities.put("bNot", "\u2AED");
+        html5Entities.put("bnot", "\u2310");
+        html5Entities.put("Bopf", "\uD835\uDD39");
+        html5Entities.put("bopf", "\uD835\uDD53");
+        html5Entities.put("bot", "\u22A5");
+        html5Entities.put("bottom", "\u22A5");
+        html5Entities.put("bowtie", "\u22C8");
+        html5Entities.put("boxbox", "\u29C9");
+        html5Entities.put("boxdl", "\u2510");
+        html5Entities.put("boxdL", "\u2555");
+        html5Entities.put("boxDl", "\u2556");
+        html5Entities.put("boxDL", "\u2557");
+        html5Entities.put("boxdr", "\u250C");
+        html5Entities.put("boxdR", "\u2552");
+        html5Entities.put("boxDr", "\u2553");
+        html5Entities.put("boxDR", "\u2554");
+        html5Entities.put("boxh", "\u2500");
+        html5Entities.put("boxH", "\u2550");
+        html5Entities.put("boxhd", "\u252C");
+        html5Entities.put("boxHd", "\u2564");
+        html5Entities.put("boxhD", "\u2565");
+        html5Entities.put("boxHD", "\u2566");
+        html5Entities.put("boxhu", "\u2534");
+        html5Entities.put("boxHu", "\u2567");
+        html5Entities.put("boxhU", "\u2568");
+        html5Entities.put("boxHU", "\u2569");
+        html5Entities.put("boxminus", "\u229F");
+        html5Entities.put("boxplus", "\u229E");
+        html5Entities.put("boxtimes", "\u22A0");
+        html5Entities.put("boxul", "\u2518");
+        html5Entities.put("boxuL", "\u255B");
+        html5Entities.put("boxUl", "\u255C");
+        html5Entities.put("boxUL", "\u255D");
+        html5Entities.put("boxur", "\u2514");
+        html5Entities.put("boxuR", "\u2558");
+        html5Entities.put("boxUr", "\u2559");
+        html5Entities.put("boxUR", "\u255A");
+        html5Entities.put("boxv", "\u2502");
+        html5Entities.put("boxV", "\u2551");
+        html5Entities.put("boxvh", "\u253C");
+        html5Entities.put("boxvH", "\u256A");
+        html5Entities.put("boxVh", "\u256B");
+        html5Entities.put("boxVH", "\u256C");
+        html5Entities.put("boxvl", "\u2524");
+        html5Entities.put("boxvL", "\u2561");
+        html5Entities.put("boxVl", "\u2562");
+        html5Entities.put("boxVL", "\u2563");
+        html5Entities.put("boxvr", "\u251C");
+        html5Entities.put("boxvR", "\u255E");
+        html5Entities.put("boxVr", "\u255F");
+        html5Entities.put("boxVR", "\u2560");
+        html5Entities.put("bprime", "\u2035");
+        html5Entities.put("breve", "\u02D8");
+        html5Entities.put("Breve", "\u02D8");
+        html5Entities.put("brvbar", "\u00A6");
+        html5Entities.put("bscr", "\uD835\uDCB7");
+        html5Entities.put("Bscr", "\u212C");
+        html5Entities.put("bsemi", "\u204F");
+        html5Entities.put("bsim", "\u223D");
+        html5Entities.put("bsime", "\u22CD");
+        html5Entities.put("bsolb", "\u29C5");
+        html5Entities.put("bsol", "\\");
+        html5Entities.put("bsolhsub", "\u27C8");
+        html5Entities.put("bull", "\u2022");
+        html5Entities.put("bullet", "\u2022");
+        html5Entities.put("bump", "\u224E");
+        html5Entities.put("bumpE", "\u2AAE");
+        html5Entities.put("bumpe", "\u224F");
+        html5Entities.put("Bumpeq", "\u224E");
+        html5Entities.put("bumpeq", "\u224F");
+        html5Entities.put("Cacute", "\u0106");
+        html5Entities.put("cacute", "\u0107");
+        html5Entities.put("capand", "\u2A44");
+        html5Entities.put("capbrcup", "\u2A49");
+        html5Entities.put("capcap", "\u2A4B");
+        html5Entities.put("cap", "\u2229");
+        html5Entities.put("Cap", "\u22D2");
+        html5Entities.put("capcup", "\u2A47");
+        html5Entities.put("capdot", "\u2A40");
+        html5Entities.put("CapitalDifferentialD", "\u2145");
+        html5Entities.put("caps", "\u2229\uFE00");
+        html5Entities.put("caret", "\u2041");
+        html5Entities.put("caron", "\u02C7");
+        html5Entities.put("Cayleys", "\u212D");
+        html5Entities.put("ccaps", "\u2A4D");
+        html5Entities.put("Ccaron", "\u010C");
+        html5Entities.put("ccaron", "\u010D");
+        html5Entities.put("Ccedil", "\u00C7");
+        html5Entities.put("ccedil", "\u00E7");
+        html5Entities.put("Ccirc", "\u0108");
+        html5Entities.put("ccirc", "\u0109");
+        html5Entities.put("Cconint", "\u2230");
+        html5Entities.put("ccups", "\u2A4C");
+        html5Entities.put("ccupssm", "\u2A50");
+        html5Entities.put("Cdot", "\u010A");
+        html5Entities.put("cdot", "\u010B");
+        html5Entities.put("cedil", "\u00B8");
+        html5Entities.put("Cedilla", "\u00B8");
+        html5Entities.put("cemptyv", "\u29B2");
+        html5Entities.put("cent", "\u00A2");
+        html5Entities.put("centerdot", "\u00B7");
+        html5Entities.put("CenterDot", "\u00B7");
+        html5Entities.put("cfr", "\uD835\uDD20");
+        html5Entities.put("Cfr", "\u212D");
+        html5Entities.put("CHcy", "\u0427");
+        html5Entities.put("chcy", "\u0447");
+        html5Entities.put("check", "\u2713");
+        html5Entities.put("checkmark", "\u2713");
+        html5Entities.put("Chi", "\u03A7");
+        html5Entities.put("chi", "\u03C7");
+        html5Entities.put("circ", "\u02C6");
+        html5Entities.put("circeq", "\u2257");
+        html5Entities.put("circlearrowleft", "\u21BA");
+        html5Entities.put("circlearrowright", "\u21BB");
+        html5Entities.put("circledast", "\u229B");
+        html5Entities.put("circledcirc", "\u229A");
+        html5Entities.put("circleddash", "\u229D");
+        html5Entities.put("CircleDot", "\u2299");
+        html5Entities.put("circledR", "\u00AE");
+        html5Entities.put("circledS", "\u24C8");
+        html5Entities.put("CircleMinus", "\u2296");
+        html5Entities.put("CirclePlus", "\u2295");
+        html5Entities.put("CircleTimes", "\u2297");
+        html5Entities.put("cir", "\u25CB");
+        html5Entities.put("cirE", "\u29C3");
+        html5Entities.put("cire", "\u2257");
+        html5Entities.put("cirfnint", "\u2A10");
+        html5Entities.put("cirmid", "\u2AEF");
+        html5Entities.put("cirscir", "\u29C2");
+        html5Entities.put("ClockwiseContourIntegral", "\u2232");
+        html5Entities.put("CloseCurlyDoubleQuote", "\u201D");
+        html5Entities.put("CloseCurlyQuote", "\u2019");
+        html5Entities.put("clubs", "\u2663");
+        html5Entities.put("clubsuit", "\u2663");
+        html5Entities.put("colon", "\u003A");
+        html5Entities.put("Colon", "\u2237");
+        html5Entities.put("Colone", "\u2A74");
+        html5Entities.put("colone", "\u2254");
+        html5Entities.put("coloneq", "\u2254");
+        html5Entities.put("comma", "\u002C");
+        html5Entities.put("commat", "\u0040");
+        html5Entities.put("comp", "\u2201");
+        html5Entities.put("compfn", "\u2218");
+        html5Entities.put("complement", "\u2201");
+        html5Entities.put("complexes", "\u2102");
+        html5Entities.put("cong", "\u2245");
+        html5Entities.put("congdot", "\u2A6D");
+        html5Entities.put("Congruent", "\u2261");
+        html5Entities.put("conint", "\u222E");
+        html5Entities.put("Conint", "\u222F");
+        html5Entities.put("ContourIntegral", "\u222E");
+        html5Entities.put("copf", "\uD835\uDD54");
+        html5Entities.put("Copf", "\u2102");
+        html5Entities.put("coprod", "\u2210");
+        html5Entities.put("Coproduct", "\u2210");
+        html5Entities.put("copy", "\u00A9");
+        html5Entities.put("COPY", "\u00A9");
+        html5Entities.put("copysr", "\u2117");
+        html5Entities.put("CounterClockwiseContourIntegral", "\u2233");
+        html5Entities.put("crarr", "\u21B5");
+        html5Entities.put("cross", "\u2717");
+        html5Entities.put("Cross", "\u2A2F");
+        html5Entities.put("Cscr", "\uD835\uDC9E");
+        html5Entities.put("cscr", "\uD835\uDCB8");
+        html5Entities.put("csub", "\u2ACF");
+        html5Entities.put("csube", "\u2AD1");
+        html5Entities.put("csup", "\u2AD0");
+        html5Entities.put("csupe", "\u2AD2");
+        html5Entities.put("ctdot", "\u22EF");
+        html5Entities.put("cudarrl", "\u2938");
+        html5Entities.put("cudarrr", "\u2935");
+        html5Entities.put("cuepr", "\u22DE");
+        html5Entities.put("cuesc", "\u22DF");
+        html5Entities.put("cularr", "\u21B6");
+        html5Entities.put("cularrp", "\u293D");
+        html5Entities.put("cupbrcap", "\u2A48");
+        html5Entities.put("cupcap", "\u2A46");
+        html5Entities.put("CupCap", "\u224D");
+        html5Entities.put("cup", "\u222A");
+        html5Entities.put("Cup", "\u22D3");
+        html5Entities.put("cupcup", "\u2A4A");
+        html5Entities.put("cupdot", "\u228D");
+        html5Entities.put("cupor", "\u2A45");
+        html5Entities.put("cups", "\u222A\uFE00");
+        html5Entities.put("curarr", "\u21B7");
+        html5Entities.put("curarrm", "\u293C");
+        html5Entities.put("curlyeqprec", "\u22DE");
+        html5Entities.put("curlyeqsucc", "\u22DF");
+        html5Entities.put("curlyvee", "\u22CE");
+        html5Entities.put("curlywedge", "\u22CF");
+        html5Entities.put("curren", "\u00A4");
+        html5Entities.put("curvearrowleft", "\u21B6");
+        html5Entities.put("curvearrowright", "\u21B7");
+        html5Entities.put("cuvee", "\u22CE");
+        html5Entities.put("cuwed", "\u22CF");
+        html5Entities.put("cwconint", "\u2232");
+        html5Entities.put("cwint", "\u2231");
+        html5Entities.put("cylcty", "\u232D");
+        html5Entities.put("dagger", "\u2020");
+        html5Entities.put("Dagger", "\u2021");
+        html5Entities.put("daleth", "\u2138");
+        html5Entities.put("darr", "\u2193");
+        html5Entities.put("Darr", "\u21A1");
+        html5Entities.put("dArr", "\u21D3");
+        html5Entities.put("dash", "\u2010");
+        html5Entities.put("Dashv", "\u2AE4");
+        html5Entities.put("dashv", "\u22A3");
+        html5Entities.put("dbkarow", "\u290F");
+        html5Entities.put("dblac", "\u02DD");
+        html5Entities.put("Dcaron", "\u010E");
+        html5Entities.put("dcaron", "\u010F");
+        html5Entities.put("Dcy", "\u0414");
+        html5Entities.put("dcy", "\u0434");
+        html5Entities.put("ddagger", "\u2021");
+        html5Entities.put("ddarr", "\u21CA");
+        html5Entities.put("DD", "\u2145");
+        html5Entities.put("dd", "\u2146");
+        html5Entities.put("DDotrahd", "\u2911");
+        html5Entities.put("ddotseq", "\u2A77");
+        html5Entities.put("deg", "\u00B0");
+        html5Entities.put("Del", "\u2207");
+        html5Entities.put("Delta", "\u0394");
+        html5Entities.put("delta", "\u03B4");
+        html5Entities.put("demptyv", "\u29B1");
+        html5Entities.put("dfisht", "\u297F");
+        html5Entities.put("Dfr", "\uD835\uDD07");
+        html5Entities.put("dfr", "\uD835\uDD21");
+        html5Entities.put("dHar", "\u2965");
+        html5Entities.put("dharl", "\u21C3");
+        html5Entities.put("dharr", "\u21C2");
+        html5Entities.put("DiacriticalAcute", "\u00B4");
+        html5Entities.put("DiacriticalDot", "\u02D9");
+        html5Entities.put("DiacriticalDoubleAcute", "\u02DD");
+        html5Entities.put("DiacriticalGrave", "\u0060");
+        html5Entities.put("DiacriticalTilde", "\u02DC");
+        html5Entities.put("diam", "\u22C4");
+        html5Entities.put("diamond", "\u22C4");
+        html5Entities.put("Diamond", "\u22C4");
+        html5Entities.put("diamondsuit", "\u2666");
+        html5Entities.put("diams", "\u2666");
+        html5Entities.put("die", "\u00A8");
+        html5Entities.put("DifferentialD", "\u2146");
+        html5Entities.put("digamma", "\u03DD");
+        html5Entities.put("disin", "\u22F2");
+        html5Entities.put("div", "\u00F7");
+        html5Entities.put("divide", "\u00F7");
+        html5Entities.put("divideontimes", "\u22C7");
+        html5Entities.put("divonx", "\u22C7");
+        html5Entities.put("DJcy", "\u0402");
+        html5Entities.put("djcy", "\u0452");
+        html5Entities.put("dlcorn", "\u231E");
+        html5Entities.put("dlcrop", "\u230D");
+        html5Entities.put("dollar", "\u0024");
+        html5Entities.put("Dopf", "\uD835\uDD3B");
+        html5Entities.put("dopf", "\uD835\uDD55");
+        html5Entities.put("Dot", "\u00A8");
+        html5Entities.put("dot", "\u02D9");
+        html5Entities.put("DotDot", "\u20DC");
+        html5Entities.put("doteq", "\u2250");
+        html5Entities.put("doteqdot", "\u2251");
+        html5Entities.put("DotEqual", "\u2250");
+        html5Entities.put("dotminus", "\u2238");
+        html5Entities.put("dotplus", "\u2214");
+        html5Entities.put("dotsquare", "\u22A1");
+        html5Entities.put("doublebarwedge", "\u2306");
+        html5Entities.put("DoubleContourIntegral", "\u222F");
+        html5Entities.put("DoubleDot", "\u00A8");
+        html5Entities.put("DoubleDownArrow", "\u21D3");
+        html5Entities.put("DoubleLeftArrow", "\u21D0");
+        html5Entities.put("DoubleLeftRightArrow", "\u21D4");
+        html5Entities.put("DoubleLeftTee", "\u2AE4");
+        html5Entities.put("DoubleLongLeftArrow", "\u27F8");
+        html5Entities.put("DoubleLongLeftRightArrow", "\u27FA");
+        html5Entities.put("DoubleLongRightArrow", "\u27F9");
+        html5Entities.put("DoubleRightArrow", "\u21D2");
+        html5Entities.put("DoubleRightTee", "\u22A8");
+        html5Entities.put("DoubleUpArrow", "\u21D1");
+        html5Entities.put("DoubleUpDownArrow", "\u21D5");
+        html5Entities.put("DoubleVerticalBar", "\u2225");
+        html5Entities.put("DownArrowBar", "\u2913");
+        html5Entities.put("downarrow", "\u2193");
+        html5Entities.put("DownArrow", "\u2193");
+        html5Entities.put("Downarrow", "\u21D3");
+        html5Entities.put("DownArrowUpArrow", "\u21F5");
+        html5Entities.put("DownBreve", "\u0311");
+        html5Entities.put("downdownarrows", "\u21CA");
+        html5Entities.put("downharpoonleft", "\u21C3");
+        html5Entities.put("downharpoonright", "\u21C2");
+        html5Entities.put("DownLeftRightVector", "\u2950");
+        html5Entities.put("DownLeftTeeVector", "\u295E");
+        html5Entities.put("DownLeftVectorBar", "\u2956");
+        html5Entities.put("DownLeftVector", "\u21BD");
+        html5Entities.put("DownRightTeeVector", "\u295F");
+        html5Entities.put("DownRightVectorBar", "\u2957");
+        html5Entities.put("DownRightVector", "\u21C1");
+        html5Entities.put("DownTeeArrow", "\u21A7");
+        html5Entities.put("DownTee", "\u22A4");
+        html5Entities.put("drbkarow", "\u2910");
+        html5Entities.put("drcorn", "\u231F");
+        html5Entities.put("drcrop", "\u230C");
+        html5Entities.put("Dscr", "\uD835\uDC9F");
+        html5Entities.put("dscr", "\uD835\uDCB9");
+        html5Entities.put("DScy", "\u0405");
+        html5Entities.put("dscy", "\u0455");
+        html5Entities.put("dsol", "\u29F6");
+        html5Entities.put("Dstrok", "\u0110");
+        html5Entities.put("dstrok", "\u0111");
+        html5Entities.put("dtdot", "\u22F1");
+        html5Entities.put("dtri", "\u25BF");
+        html5Entities.put("dtrif", "\u25BE");
+        html5Entities.put("duarr", "\u21F5");
+        html5Entities.put("duhar", "\u296F");
+        html5Entities.put("dwangle", "\u29A6");
+        html5Entities.put("DZcy", "\u040F");
+        html5Entities.put("dzcy", "\u045F");
+        html5Entities.put("dzigrarr", "\u27FF");
+        html5Entities.put("Eacute", "\u00C9");
+        html5Entities.put("eacute", "\u00E9");
+        html5Entities.put("easter", "\u2A6E");
+        html5Entities.put("Ecaron", "\u011A");
+        html5Entities.put("ecaron", "\u011B");
+        html5Entities.put("Ecirc", "\u00CA");
+        html5Entities.put("ecirc", "\u00EA");
+        html5Entities.put("ecir", "\u2256");
+        html5Entities.put("ecolon", "\u2255");
+        html5Entities.put("Ecy", "\u042D");
+        html5Entities.put("ecy", "\u044D");
+        html5Entities.put("eDDot", "\u2A77");
+        html5Entities.put("Edot", "\u0116");
+        html5Entities.put("edot", "\u0117");
+        html5Entities.put("eDot", "\u2251");
+        html5Entities.put("ee", "\u2147");
+        html5Entities.put("efDot", "\u2252");
+        html5Entities.put("Efr", "\uD835\uDD08");
+        html5Entities.put("efr", "\uD835\uDD22");
+        html5Entities.put("eg", "\u2A9A");
+        html5Entities.put("Egrave", "\u00C8");
+        html5Entities.put("egrave", "\u00E8");
+        html5Entities.put("egs", "\u2A96");
+        html5Entities.put("egsdot", "\u2A98");
+        html5Entities.put("el", "\u2A99");
+        html5Entities.put("Element", "\u2208");
+        html5Entities.put("elinters", "\u23E7");
+        html5Entities.put("ell", "\u2113");
+        html5Entities.put("els", "\u2A95");
+        html5Entities.put("elsdot", "\u2A97");
+        html5Entities.put("Emacr", "\u0112");
+        html5Entities.put("emacr", "\u0113");
+        html5Entities.put("empty", "\u2205");
+        html5Entities.put("emptyset", "\u2205");
+        html5Entities.put("EmptySmallSquare", "\u25FB");
+        html5Entities.put("emptyv", "\u2205");
+        html5Entities.put("EmptyVerySmallSquare", "\u25AB");
+        html5Entities.put("emsp13", "\u2004");
+        html5Entities.put("emsp14", "\u2005");
+        html5Entities.put("emsp", "\u2003");
+        html5Entities.put("ENG", "\u014A");
+        html5Entities.put("eng", "\u014B");
+        html5Entities.put("ensp", "\u2002");
+        html5Entities.put("Eogon", "\u0118");
+        html5Entities.put("eogon", "\u0119");
+        html5Entities.put("Eopf", "\uD835\uDD3C");
+        html5Entities.put("eopf", "\uD835\uDD56");
+        html5Entities.put("epar", "\u22D5");
+        html5Entities.put("eparsl", "\u29E3");
+        html5Entities.put("eplus", "\u2A71");
+        html5Entities.put("epsi", "\u03B5");
+        html5Entities.put("Epsilon", "\u0395");
+        html5Entities.put("epsilon", "\u03B5");
+        html5Entities.put("epsiv", "\u03F5");
+        html5Entities.put("eqcirc", "\u2256");
+        html5Entities.put("eqcolon", "\u2255");
+        html5Entities.put("eqsim", "\u2242");
+        html5Entities.put("eqslantgtr", "\u2A96");
+        html5Entities.put("eqslantless", "\u2A95");
+        html5Entities.put("Equal", "\u2A75");
+        html5Entities.put("equals", "\u003D");
+        html5Entities.put("EqualTilde", "\u2242");
+        html5Entities.put("equest", "\u225F");
+        html5Entities.put("Equilibrium", "\u21CC");
+        html5Entities.put("equiv", "\u2261");
+        html5Entities.put("equivDD", "\u2A78");
+        html5Entities.put("eqvparsl", "\u29E5");
+        html5Entities.put("erarr", "\u2971");
+        html5Entities.put("erDot", "\u2253");
+        html5Entities.put("escr", "\u212F");
+        html5Entities.put("Escr", "\u2130");
+        html5Entities.put("esdot", "\u2250");
+        html5Entities.put("Esim", "\u2A73");
+        html5Entities.put("esim", "\u2242");
+        html5Entities.put("Eta", "\u0397");
+        html5Entities.put("eta", "\u03B7");
+        html5Entities.put("ETH", "\u00D0");
+        html5Entities.put("eth", "\u00F0");
+        html5Entities.put("Euml", "\u00CB");
+        html5Entities.put("euml", "\u00EB");
+        html5Entities.put("euro", "\u20AC");
+        html5Entities.put("excl", "\u0021");
+        html5Entities.put("exist", "\u2203");
+        html5Entities.put("Exists", "\u2203");
+        html5Entities.put("expectation", "\u2130");
+        html5Entities.put("exponentiale", "\u2147");
+        html5Entities.put("ExponentialE", "\u2147");
+        html5Entities.put("fallingdotseq", "\u2252");
+        html5Entities.put("Fcy", "\u0424");
+        html5Entities.put("fcy", "\u0444");
+        html5Entities.put("female", "\u2640");
+        html5Entities.put("ffilig", "\uFB03");
+        html5Entities.put("fflig", "\uFB00");
+        html5Entities.put("ffllig", "\uFB04");
+        html5Entities.put("Ffr", "\uD835\uDD09");
+        html5Entities.put("ffr", "\uD835\uDD23");
+        html5Entities.put("filig", "\uFB01");
+        html5Entities.put("FilledSmallSquare", "\u25FC");
+        html5Entities.put("FilledVerySmallSquare", "\u25AA");
+        html5Entities.put("fjlig", "\u0066\u006A");
+        html5Entities.put("flat", "\u266D");
+        html5Entities.put("fllig", "\uFB02");
+        html5Entities.put("fltns", "\u25B1");
+        html5Entities.put("fnof", "\u0192");
+        html5Entities.put("Fopf", "\uD835\uDD3D");
+        html5Entities.put("fopf", "\uD835\uDD57");
+        html5Entities.put("forall", "\u2200");
+        html5Entities.put("ForAll", "\u2200");
+        html5Entities.put("fork", "\u22D4");
+        html5Entities.put("forkv", "\u2AD9");
+        html5Entities.put("Fouriertrf", "\u2131");
+        html5Entities.put("fpartint", "\u2A0D");
+        html5Entities.put("frac12", "\u00BD");
+        html5Entities.put("frac13", "\u2153");
+        html5Entities.put("frac14", "\u00BC");
+        html5Entities.put("frac15", "\u2155");
+        html5Entities.put("frac16", "\u2159");
+        html5Entities.put("frac18", "\u215B");
+        html5Entities.put("frac23", "\u2154");
+        html5Entities.put("frac25", "\u2156");
+        html5Entities.put("frac34", "\u00BE");
+        html5Entities.put("frac35", "\u2157");
+        html5Entities.put("frac38", "\u215C");
+        html5Entities.put("frac45", "\u2158");
+        html5Entities.put("frac56", "\u215A");
+        html5Entities.put("frac58", "\u215D");
+        html5Entities.put("frac78", "\u215E");
+        html5Entities.put("frasl", "\u2044");
+        html5Entities.put("frown", "\u2322");
+        html5Entities.put("fscr", "\uD835\uDCBB");
+        html5Entities.put("Fscr", "\u2131");
+        html5Entities.put("gacute", "\u01F5");
+        html5Entities.put("Gamma", "\u0393");
+        html5Entities.put("gamma", "\u03B3");
+        html5Entities.put("Gammad", "\u03DC");
+        html5Entities.put("gammad", "\u03DD");
+        html5Entities.put("gap", "\u2A86");
+        html5Entities.put("Gbreve", "\u011E");
+        html5Entities.put("gbreve", "\u011F");
+        html5Entities.put("Gcedil", "\u0122");
+        html5Entities.put("Gcirc", "\u011C");
+        html5Entities.put("gcirc", "\u011D");
+        html5Entities.put("Gcy", "\u0413");
+        html5Entities.put("gcy", "\u0433");
+        html5Entities.put("Gdot", "\u0120");
+        html5Entities.put("gdot", "\u0121");
+        html5Entities.put("ge", "\u2265");
+        html5Entities.put("gE", "\u2267");
+        html5Entities.put("gEl", "\u2A8C");
+        html5Entities.put("gel", "\u22DB");
+        html5Entities.put("geq", "\u2265");
+        html5Entities.put("geqq", "\u2267");
+        html5Entities.put("geqslant", "\u2A7E");
+        html5Entities.put("gescc", "\u2AA9");
+        html5Entities.put("ges", "\u2A7E");
+        html5Entities.put("gesdot", "\u2A80");
+        html5Entities.put("gesdoto", "\u2A82");
+        html5Entities.put("gesdotol", "\u2A84");
+        html5Entities.put("gesl", "\u22DB\uFE00");
+        html5Entities.put("gesles", "\u2A94");
+        html5Entities.put("Gfr", "\uD835\uDD0A");
+        html5Entities.put("gfr", "\uD835\uDD24");
+        html5Entities.put("gg", "\u226B");
+        html5Entities.put("Gg", "\u22D9");
+        html5Entities.put("ggg", "\u22D9");
+        html5Entities.put("gimel", "\u2137");
+        html5Entities.put("GJcy", "\u0403");
+        html5Entities.put("gjcy", "\u0453");
+        html5Entities.put("gla", "\u2AA5");
+        html5Entities.put("gl", "\u2277");
+        html5Entities.put("glE", "\u2A92");
+        html5Entities.put("glj", "\u2AA4");
+        html5Entities.put("gnap", "\u2A8A");
+        html5Entities.put("gnapprox", "\u2A8A");
+        html5Entities.put("gne", "\u2A88");
+        html5Entities.put("gnE", "\u2269");
+        html5Entities.put("gneq", "\u2A88");
+        html5Entities.put("gneqq", "\u2269");
+        html5Entities.put("gnsim", "\u22E7");
+        html5Entities.put("Gopf", "\uD835\uDD3E");
+        html5Entities.put("gopf", "\uD835\uDD58");
+        html5Entities.put("grave", "\u0060");
+        html5Entities.put("GreaterEqual", "\u2265");
+        html5Entities.put("GreaterEqualLess", "\u22DB");
+        html5Entities.put("GreaterFullEqual", "\u2267");
+        html5Entities.put("GreaterGreater", "\u2AA2");
+        html5Entities.put("GreaterLess", "\u2277");
+        html5Entities.put("GreaterSlantEqual", "\u2A7E");
+        html5Entities.put("GreaterTilde", "\u2273");
+        html5Entities.put("Gscr", "\uD835\uDCA2");
+        html5Entities.put("gscr", "\u210A");
+        html5Entities.put("gsim", "\u2273");
+        html5Entities.put("gsime", "\u2A8E");
+        html5Entities.put("gsiml", "\u2A90");
+        html5Entities.put("gtcc", "\u2AA7");
+        html5Entities.put("gtcir", "\u2A7A");
+        html5Entities.put("gt", "\u003E");
+        html5Entities.put("GT", "\u003E");
+        html5Entities.put("Gt", "\u226B");
+        html5Entities.put("gtdot", "\u22D7");
+        html5Entities.put("gtlPar", "\u2995");
+        html5Entities.put("gtquest", "\u2A7C");
+        html5Entities.put("gtrapprox", "\u2A86");
+        html5Entities.put("gtrarr", "\u2978");
+        html5Entities.put("gtrdot", "\u22D7");
+        html5Entities.put("gtreqless", "\u22DB");
+        html5Entities.put("gtreqqless", "\u2A8C");
+        html5Entities.put("gtrless", "\u2277");
+        html5Entities.put("gtrsim", "\u2273");
+        html5Entities.put("gvertneqq", "\u2269\uFE00");
+        html5Entities.put("gvnE", "\u2269\uFE00");
+        html5Entities.put("Hacek", "\u02C7");
+        html5Entities.put("hairsp", "\u200A");
+        html5Entities.put("half", "\u00BD");
+        html5Entities.put("hamilt", "\u210B");
+        html5Entities.put("HARDcy", "\u042A");
+        html5Entities.put("hardcy", "\u044A");
+        html5Entities.put("harrcir", "\u2948");
+        html5Entities.put("harr", "\u2194");
+        html5Entities.put("hArr", "\u21D4");
+        html5Entities.put("harrw", "\u21AD");
+        html5Entities.put("Hat", "\u005E");
+        html5Entities.put("hbar", "\u210F");
+        html5Entities.put("Hcirc", "\u0124");
+        html5Entities.put("hcirc", "\u0125");
+        html5Entities.put("hearts", "\u2665");
+        html5Entities.put("heartsuit", "\u2665");
+        html5Entities.put("hellip", "\u2026");
+        html5Entities.put("hercon", "\u22B9");
+        html5Entities.put("hfr", "\uD835\uDD25");
+        html5Entities.put("Hfr", "\u210C");
+        html5Entities.put("HilbertSpace", "\u210B");
+        html5Entities.put("hksearow", "\u2925");
+        html5Entities.put("hkswarow", "\u2926");
+        html5Entities.put("hoarr", "\u21FF");
+        html5Entities.put("homtht", "\u223B");
+        html5Entities.put("hookleftarrow", "\u21A9");
+        html5Entities.put("hookrightarrow", "\u21AA");
+        html5Entities.put("hopf", "\uD835\uDD59");
+        html5Entities.put("Hopf", "\u210D");
+        html5Entities.put("horbar", "\u2015");
+        html5Entities.put("HorizontalLine", "\u2500");
+        html5Entities.put("hscr", "\uD835\uDCBD");
+        html5Entities.put("Hscr", "\u210B");
+        html5Entities.put("hslash", "\u210F");
+        html5Entities.put("Hstrok", "\u0126");
+        html5Entities.put("hstrok", "\u0127");
+        html5Entities.put("HumpDownHump", "\u224E");
+        html5Entities.put("HumpEqual", "\u224F");
+        html5Entities.put("hybull", "\u2043");
+        html5Entities.put("hyphen", "\u2010");
+        html5Entities.put("Iacute", "\u00CD");
+        html5Entities.put("iacute", "\u00ED");
+        html5Entities.put("ic", "\u2063");
+        html5Entities.put("Icirc", "\u00CE");
+        html5Entities.put("icirc", "\u00EE");
+        html5Entities.put("Icy", "\u0418");
+        html5Entities.put("icy", "\u0438");
+        html5Entities.put("Idot", "\u0130");
+        html5Entities.put("IEcy", "\u0415");
+        html5Entities.put("iecy", "\u0435");
+        html5Entities.put("iexcl", "\u00A1");
+        html5Entities.put("iff", "\u21D4");
+        html5Entities.put("ifr", "\uD835\uDD26");
+        html5Entities.put("Ifr", "\u2111");
+        html5Entities.put("Igrave", "\u00CC");
+        html5Entities.put("igrave", "\u00EC");
+        html5Entities.put("ii", "\u2148");
+        html5Entities.put("iiiint", "\u2A0C");
+        html5Entities.put("iiint", "\u222D");
+        html5Entities.put("iinfin", "\u29DC");
+        html5Entities.put("iiota", "\u2129");
+        html5Entities.put("IJlig", "\u0132");
+        html5Entities.put("ijlig", "\u0133");
+        html5Entities.put("Imacr", "\u012A");
+        html5Entities.put("imacr", "\u012B");
+        html5Entities.put("image", "\u2111");
+        html5Entities.put("ImaginaryI", "\u2148");
+        html5Entities.put("imagline", "\u2110");
+        html5Entities.put("imagpart", "\u2111");
+        html5Entities.put("imath", "\u0131");
+        html5Entities.put("Im", "\u2111");
+        html5Entities.put("imof", "\u22B7");
+        html5Entities.put("imped", "\u01B5");
+        html5Entities.put("Implies", "\u21D2");
+        html5Entities.put("incare", "\u2105");
+        html5Entities.put("in", "\u2208");
+        html5Entities.put("infin", "\u221E");
+        html5Entities.put("infintie", "\u29DD");
+        html5Entities.put("inodot", "\u0131");
+        html5Entities.put("intcal", "\u22BA");
+        html5Entities.put("int", "\u222B");
+        html5Entities.put("Int", "\u222C");
+        html5Entities.put("integers", "\u2124");
+        html5Entities.put("Integral", "\u222B");
+        html5Entities.put("intercal", "\u22BA");
+        html5Entities.put("Intersection", "\u22C2");
+        html5Entities.put("intlarhk", "\u2A17");
+        html5Entities.put("intprod", "\u2A3C");
+        html5Entities.put("InvisibleComma", "\u2063");
+        html5Entities.put("InvisibleTimes", "\u2062");
+        html5Entities.put("IOcy", "\u0401");
+        html5Entities.put("iocy", "\u0451");
+        html5Entities.put("Iogon", "\u012E");
+        html5Entities.put("iogon", "\u012F");
+        html5Entities.put("Iopf", "\uD835\uDD40");
+        html5Entities.put("iopf", "\uD835\uDD5A");
+        html5Entities.put("Iota", "\u0399");
+        html5Entities.put("iota", "\u03B9");
+        html5Entities.put("iprod", "\u2A3C");
+        html5Entities.put("iquest", "\u00BF");
+        html5Entities.put("iscr", "\uD835\uDCBE");
+        html5Entities.put("Iscr", "\u2110");
+        html5Entities.put("isin", "\u2208");
+        html5Entities.put("isindot", "\u22F5");
+        html5Entities.put("isinE", "\u22F9");
+        html5Entities.put("isins", "\u22F4");
+        html5Entities.put("isinsv", "\u22F3");
+        html5Entities.put("isinv", "\u2208");
+        html5Entities.put("it", "\u2062");
+        html5Entities.put("Itilde", "\u0128");
+        html5Entities.put("itilde", "\u0129");
+        html5Entities.put("Iukcy", "\u0406");
+        html5Entities.put("iukcy", "\u0456");
+        html5Entities.put("Iuml", "\u00CF");
+        html5Entities.put("iuml", "\u00EF");
+        html5Entities.put("Jcirc", "\u0134");
+        html5Entities.put("jcirc", "\u0135");
+        html5Entities.put("Jcy", "\u0419");
+        html5Entities.put("jcy", "\u0439");
+        html5Entities.put("Jfr", "\uD835\uDD0D");
+        html5Entities.put("jfr", "\uD835\uDD27");
+        html5Entities.put("jmath", "\u0237");
+        html5Entities.put("Jopf", "\uD835\uDD41");
+        html5Entities.put("jopf", "\uD835\uDD5B");
+        html5Entities.put("Jscr", "\uD835\uDCA5");
+        html5Entities.put("jscr", "\uD835\uDCBF");
+        html5Entities.put("Jsercy", "\u0408");
+        html5Entities.put("jsercy", "\u0458");
+        html5Entities.put("Jukcy", "\u0404");
+        html5Entities.put("jukcy", "\u0454");
+        html5Entities.put("Kappa", "\u039A");
+        html5Entities.put("kappa", "\u03BA");
+        html5Entities.put("kappav", "\u03F0");
+        html5Entities.put("Kcedil", "\u0136");
+        html5Entities.put("kcedil", "\u0137");
+        html5Entities.put("Kcy", "\u041A");
+        html5Entities.put("kcy", "\u043A");
+        html5Entities.put("Kfr", "\uD835\uDD0E");
+        html5Entities.put("kfr", "\uD835\uDD28");
+        html5Entities.put("kgreen", "\u0138");
+        html5Entities.put("KHcy", "\u0425");
+        html5Entities.put("khcy", "\u0445");
+        html5Entities.put("KJcy", "\u040C");
+        html5Entities.put("kjcy", "\u045C");
+        html5Entities.put("Kopf", "\uD835\uDD42");
+        html5Entities.put("kopf", "\uD835\uDD5C");
+        html5Entities.put("Kscr", "\uD835\uDCA6");
+        html5Entities.put("kscr", "\uD835\uDCC0");
+        html5Entities.put("lAarr", "\u21DA");
+        html5Entities.put("Lacute", "\u0139");
+        html5Entities.put("lacute", "\u013A");
+        html5Entities.put("laemptyv", "\u29B4");
+        html5Entities.put("lagran", "\u2112");
+        html5Entities.put("Lambda", "\u039B");
+        html5Entities.put("lambda", "\u03BB");
+        html5Entities.put("lang", "\u27E8");
+        html5Entities.put("Lang", "\u27EA");
+        html5Entities.put("langd", "\u2991");
+        html5Entities.put("langle", "\u27E8");
+        html5Entities.put("lap", "\u2A85");
+        html5Entities.put("Laplacetrf", "\u2112");
+        html5Entities.put("laquo", "\u00AB");
+        html5Entities.put("larrb", "\u21E4");
+        html5Entities.put("larrbfs", "\u291F");
+        html5Entities.put("larr", "\u2190");
+        html5Entities.put("Larr", "\u219E");
+        html5Entities.put("lArr", "\u21D0");
+        html5Entities.put("larrfs", "\u291D");
+        html5Entities.put("larrhk", "\u21A9");
+        html5Entities.put("larrlp", "\u21AB");
+        html5Entities.put("larrpl", "\u2939");
+        html5Entities.put("larrsim", "\u2973");
+        html5Entities.put("larrtl", "\u21A2");
+        html5Entities.put("latail", "\u2919");
+        html5Entities.put("lAtail", "\u291B");
+        html5Entities.put("lat", "\u2AAB");
+        html5Entities.put("late", "\u2AAD");
+        html5Entities.put("lates", "\u2AAD\uFE00");
+        html5Entities.put("lbarr", "\u290C");
+        html5Entities.put("lBarr", "\u290E");
+        html5Entities.put("lbbrk", "\u2772");
+        html5Entities.put("lbrace", "\u007B");
+        html5Entities.put("lbrack", "\u005B");
+        html5Entities.put("lbrke", "\u298B");
+        html5Entities.put("lbrksld", "\u298F");
+        html5Entities.put("lbrkslu", "\u298D");
+        html5Entities.put("Lcaron", "\u013D");
+        html5Entities.put("lcaron", "\u013E");
+        html5Entities.put("Lcedil", "\u013B");
+        html5Entities.put("lcedil", "\u013C");
+        html5Entities.put("lceil", "\u2308");
+        html5Entities.put("lcub", "\u007B");
+        html5Entities.put("Lcy", "\u041B");
+        html5Entities.put("lcy", "\u043B");
+        html5Entities.put("ldca", "\u2936");
+        html5Entities.put("ldquo", "\u201C");
+        html5Entities.put("ldquor", "\u201E");
+        html5Entities.put("ldrdhar", "\u2967");
+        html5Entities.put("ldrushar", "\u294B");
+        html5Entities.put("ldsh", "\u21B2");
+        html5Entities.put("le", "\u2264");
+        html5Entities.put("lE", "\u2266");
+        html5Entities.put("LeftAngleBracket", "\u27E8");
+        html5Entities.put("LeftArrowBar", "\u21E4");
+        html5Entities.put("leftarrow", "\u2190");
+        html5Entities.put("LeftArrow", "\u2190");
+        html5Entities.put("Leftarrow", "\u21D0");
+        html5Entities.put("LeftArrowRightArrow", "\u21C6");
+        html5Entities.put("leftarrowtail", "\u21A2");
+        html5Entities.put("LeftCeiling", "\u2308");
+        html5Entities.put("LeftDoubleBracket", "\u27E6");
+        html5Entities.put("LeftDownTeeVector", "\u2961");
+        html5Entities.put("LeftDownVectorBar", "\u2959");
+        html5Entities.put("LeftDownVector", "\u21C3");
+        html5Entities.put("LeftFloor", "\u230A");
+        html5Entities.put("leftharpoondown", "\u21BD");
+        html5Entities.put("leftharpoonup", "\u21BC");
+        html5Entities.put("leftleftarrows", "\u21C7");
+        html5Entities.put("leftrightarrow", "\u2194");
+        html5Entities.put("LeftRightArrow", "\u2194");
+        html5Entities.put("Leftrightarrow", "\u21D4");
+        html5Entities.put("leftrightarrows", "\u21C6");
+        html5Entities.put("leftrightharpoons", "\u21CB");
+        html5Entities.put("leftrightsquigarrow", "\u21AD");
+        html5Entities.put("LeftRightVector", "\u294E");
+        html5Entities.put("LeftTeeArrow", "\u21A4");
+        html5Entities.put("LeftTee", "\u22A3");
+        html5Entities.put("LeftTeeVector", "\u295A");
+        html5Entities.put("leftthreetimes", "\u22CB");
+        html5Entities.put("LeftTriangleBar", "\u29CF");
+        html5Entities.put("LeftTriangle", "\u22B2");
+        html5Entities.put("LeftTriangleEqual", "\u22B4");
+        html5Entities.put("LeftUpDownVector", "\u2951");
+        html5Entities.put("LeftUpTeeVector", "\u2960");
+        html5Entities.put("LeftUpVectorBar", "\u2958");
+        html5Entities.put("LeftUpVector", "\u21BF");
+        html5Entities.put("LeftVectorBar", "\u2952");
+        html5Entities.put("LeftVector", "\u21BC");
+        html5Entities.put("lEg", "\u2A8B");
+        html5Entities.put("leg", "\u22DA");
+        html5Entities.put("leq", "\u2264");
+        html5Entities.put("leqq", "\u2266");
+        html5Entities.put("leqslant", "\u2A7D");
+        html5Entities.put("lescc", "\u2AA8");
+        html5Entities.put("les", "\u2A7D");
+        html5Entities.put("lesdot", "\u2A7F");
+        html5Entities.put("lesdoto", "\u2A81");
+        html5Entities.put("lesdotor", "\u2A83");
+        html5Entities.put("lesg", "\u22DA\uFE00");
+        html5Entities.put("lesges", "\u2A93");
+        html5Entities.put("lessapprox", "\u2A85");
+        html5Entities.put("lessdot", "\u22D6");
+        html5Entities.put("lesseqgtr", "\u22DA");
+        html5Entities.put("lesseqqgtr", "\u2A8B");
+        html5Entities.put("LessEqualGreater", "\u22DA");
+        html5Entities.put("LessFullEqual", "\u2266");
+        html5Entities.put("LessGreater", "\u2276");
+        html5Entities.put("lessgtr", "\u2276");
+        html5Entities.put("LessLess", "\u2AA1");
+        html5Entities.put("lesssim", "\u2272");
+        html5Entities.put("LessSlantEqual", "\u2A7D");
+        html5Entities.put("LessTilde", "\u2272");
+        html5Entities.put("lfisht", "\u297C");
+        html5Entities.put("lfloor", "\u230A");
+        html5Entities.put("Lfr", "\uD835\uDD0F");
+        html5Entities.put("lfr", "\uD835\uDD29");
+        html5Entities.put("lg", "\u2276");
+        html5Entities.put("lgE", "\u2A91");
+        html5Entities.put("lHar", "\u2962");
+        html5Entities.put("lhard", "\u21BD");
+        html5Entities.put("lharu", "\u21BC");
+        html5Entities.put("lharul", "\u296A");
+        html5Entities.put("lhblk", "\u2584");
+        html5Entities.put("LJcy", "\u0409");
+        html5Entities.put("ljcy", "\u0459");
+        html5Entities.put("llarr", "\u21C7");
+        html5Entities.put("ll", "\u226A");
+        html5Entities.put("Ll", "\u22D8");
+        html5Entities.put("llcorner", "\u231E");
+        html5Entities.put("Lleftarrow", "\u21DA");
+        html5Entities.put("llhard", "\u296B");
+        html5Entities.put("lltri", "\u25FA");
+        html5Entities.put("Lmidot", "\u013F");
+        html5Entities.put("lmidot", "\u0140");
+        html5Entities.put("lmoustache", "\u23B0");
+        html5Entities.put("lmoust", "\u23B0");
+        html5Entities.put("lnap", "\u2A89");
+        html5Entities.put("lnapprox", "\u2A89");
+        html5Entities.put("lne", "\u2A87");
+        html5Entities.put("lnE", "\u2268");
+        html5Entities.put("lneq", "\u2A87");
+        html5Entities.put("lneqq", "\u2268");
+        html5Entities.put("lnsim", "\u22E6");
+        html5Entities.put("loang", "\u27EC");
+        html5Entities.put("loarr", "\u21FD");
+        html5Entities.put("lobrk", "\u27E6");
+        html5Entities.put("longleftarrow", "\u27F5");
+        html5Entities.put("LongLeftArrow", "\u27F5");
+        html5Entities.put("Longleftarrow", "\u27F8");
+        html5Entities.put("longleftrightarrow", "\u27F7");
+        html5Entities.put("LongLeftRightArrow", "\u27F7");
+        html5Entities.put("Longleftrightarrow", "\u27FA");
+        html5Entities.put("longmapsto", "\u27FC");
+        html5Entities.put("longrightarrow", "\u27F6");
+        html5Entities.put("LongRightArrow", "\u27F6");
+        html5Entities.put("Longrightarrow", "\u27F9");
+        html5Entities.put("looparrowleft", "\u21AB");
+        html5Entities.put("looparrowright", "\u21AC");
+        html5Entities.put("lopar", "\u2985");
+        html5Entities.put("Lopf", "\uD835\uDD43");
+        html5Entities.put("lopf", "\uD835\uDD5D");
+        html5Entities.put("loplus", "\u2A2D");
+        html5Entities.put("lotimes", "\u2A34");
+        html5Entities.put("lowast", "\u2217");
+        html5Entities.put("lowbar", "\u005F");
+        html5Entities.put("LowerLeftArrow", "\u2199");
+        html5Entities.put("LowerRightArrow", "\u2198");
+        html5Entities.put("loz", "\u25CA");
+        html5Entities.put("lozenge", "\u25CA");
+        html5Entities.put("lozf", "\u29EB");
+        html5Entities.put("lpar", "\u0028");
+        html5Entities.put("lparlt", "\u2993");
+        html5Entities.put("lrarr", "\u21C6");
+        html5Entities.put("lrcorner", "\u231F");
+        html5Entities.put("lrhar", "\u21CB");
+        html5Entities.put("lrhard", "\u296D");
+        html5Entities.put("lrm", "\u200E");
+        html5Entities.put("lrtri", "\u22BF");
+        html5Entities.put("lsaquo", "\u2039");
+        html5Entities.put("lscr", "\uD835\uDCC1");
+        html5Entities.put("Lscr", "\u2112");
+        html5Entities.put("lsh", "\u21B0");
+        html5Entities.put("Lsh", "\u21B0");
+        html5Entities.put("lsim", "\u2272");
+        html5Entities.put("lsime", "\u2A8D");
+        html5Entities.put("lsimg", "\u2A8F");
+        html5Entities.put("lsqb", "\u005B");
+        html5Entities.put("lsquo", "\u2018");
+        html5Entities.put("lsquor", "\u201A");
+        html5Entities.put("Lstrok", "\u0141");
+        html5Entities.put("lstrok", "\u0142");
+        html5Entities.put("ltcc", "\u2AA6");
+        html5Entities.put("ltcir", "\u2A79");
+        html5Entities.put("lt", "\u003C");
+        html5Entities.put("LT", "\u003C");
+        html5Entities.put("Lt", "\u226A");
+        html5Entities.put("ltdot", "\u22D6");
+        html5Entities.put("lthree", "\u22CB");
+        html5Entities.put("ltimes", "\u22C9");
+        html5Entities.put("ltlarr", "\u2976");
+        html5Entities.put("ltquest", "\u2A7B");
+        html5Entities.put("ltri", "\u25C3");
+        html5Entities.put("ltrie", "\u22B4");
+        html5Entities.put("ltrif", "\u25C2");
+        html5Entities.put("ltrPar", "\u2996");
+        html5Entities.put("lurdshar", "\u294A");
+        html5Entities.put("luruhar", "\u2966");
+        html5Entities.put("lvertneqq", "\u2268\uFE00");
+        html5Entities.put("lvnE", "\u2268\uFE00");
+        html5Entities.put("macr", "\u00AF");
+        html5Entities.put("male", "\u2642");
+        html5Entities.put("malt", "\u2720");
+        html5Entities.put("maltese", "\u2720");
+        html5Entities.put("Map", "\u2905");
+        html5Entities.put("map", "\u21A6");
+        html5Entities.put("mapsto", "\u21A6");
+        html5Entities.put("mapstodown", "\u21A7");
+        html5Entities.put("mapstoleft", "\u21A4");
+        html5Entities.put("mapstoup", "\u21A5");
+        html5Entities.put("marker", "\u25AE");
+        html5Entities.put("mcomma", "\u2A29");
+        html5Entities.put("Mcy", "\u041C");
+        html5Entities.put("mcy", "\u043C");
+        html5Entities.put("mdash", "\u2014");
+        html5Entities.put("mDDot", "\u223A");
+        html5Entities.put("measuredangle", "\u2221");
+        html5Entities.put("MediumSpace", "\u205F");
+        html5Entities.put("Mellintrf", "\u2133");
+        html5Entities.put("Mfr", "\uD835\uDD10");
+        html5Entities.put("mfr", "\uD835\uDD2A");
+        html5Entities.put("mho", "\u2127");
+        html5Entities.put("micro", "\u00B5");
+        html5Entities.put("midast", "\u002A");
+        html5Entities.put("midcir", "\u2AF0");
+        html5Entities.put("mid", "\u2223");
+        html5Entities.put("middot", "\u00B7");
+        html5Entities.put("minusb", "\u229F");
+        html5Entities.put("minus", "\u2212");
+        html5Entities.put("minusd", "\u2238");
+        html5Entities.put("minusdu", "\u2A2A");
+        html5Entities.put("MinusPlus", "\u2213");
+        html5Entities.put("mlcp", "\u2ADB");
+        html5Entities.put("mldr", "\u2026");
+        html5Entities.put("mnplus", "\u2213");
+        html5Entities.put("models", "\u22A7");
+        html5Entities.put("Mopf", "\uD835\uDD44");
+        html5Entities.put("mopf", "\uD835\uDD5E");
+        html5Entities.put("mp", "\u2213");
+        html5Entities.put("mscr", "\uD835\uDCC2");
+        html5Entities.put("Mscr", "\u2133");
+        html5Entities.put("mstpos", "\u223E");
+        html5Entities.put("Mu", "\u039C");
+        html5Entities.put("mu", "\u03BC");
+        html5Entities.put("multimap", "\u22B8");
+        html5Entities.put("mumap", "\u22B8");
+        html5Entities.put("nabla", "\u2207");
+        html5Entities.put("Nacute", "\u0143");
+        html5Entities.put("nacute", "\u0144");
+        html5Entities.put("nang", "\u2220\u20D2");
+        html5Entities.put("nap", "\u2249");
+        html5Entities.put("napE", "\u2A70\u0338");
+        html5Entities.put("napid", "\u224B\u0338");
+        html5Entities.put("napos", "\u0149");
+        html5Entities.put("napprox", "\u2249");
+        html5Entities.put("natural", "\u266E");
+        html5Entities.put("naturals", "\u2115");
+        html5Entities.put("natur", "\u266E");
+        html5Entities.put("nbsp", "\u00A0");
+        html5Entities.put("nbump", "\u224E\u0338");
+        html5Entities.put("nbumpe", "\u224F\u0338");
+        html5Entities.put("ncap", "\u2A43");
+        html5Entities.put("Ncaron", "\u0147");
+        html5Entities.put("ncaron", "\u0148");
+        html5Entities.put("Ncedil", "\u0145");
+        html5Entities.put("ncedil", "\u0146");
+        html5Entities.put("ncong", "\u2247");
+        html5Entities.put("ncongdot", "\u2A6D\u0338");
+        html5Entities.put("ncup", "\u2A42");
+        html5Entities.put("Ncy", "\u041D");
+        html5Entities.put("ncy", "\u043D");
+        html5Entities.put("ndash", "\u2013");
+        html5Entities.put("nearhk", "\u2924");
+        html5Entities.put("nearr", "\u2197");
+        html5Entities.put("neArr", "\u21D7");
+        html5Entities.put("nearrow", "\u2197");
+        html5Entities.put("ne", "\u2260");
+        html5Entities.put("nedot", "\u2250\u0338");
+        html5Entities.put("NegativeMediumSpace", "\u200B");
+        html5Entities.put("NegativeThickSpace", "\u200B");
+        html5Entities.put("NegativeThinSpace", "\u200B");
+        html5Entities.put("NegativeVeryThinSpace", "\u200B");
+        html5Entities.put("nequiv", "\u2262");
+        html5Entities.put("nesear", "\u2928");
+        html5Entities.put("nesim", "\u2242\u0338");
+        html5Entities.put("NestedGreaterGreater", "\u226B");
+        html5Entities.put("NestedLessLess", "\u226A");
+        html5Entities.put("NewLine", "\n");
+        html5Entities.put("nexist", "\u2204");
+        html5Entities.put("nexists", "\u2204");
+        html5Entities.put("Nfr", "\uD835\uDD11");
+        html5Entities.put("nfr", "\uD835\uDD2B");
+        html5Entities.put("ngE", "\u2267\u0338");
+        html5Entities.put("nge", "\u2271");
+        html5Entities.put("ngeq", "\u2271");
+        html5Entities.put("ngeqq", "\u2267\u0338");
+        html5Entities.put("ngeqslant", "\u2A7E\u0338");
+        html5Entities.put("nges", "\u2A7E\u0338");
+        html5Entities.put("nGg", "\u22D9\u0338");
+        html5Entities.put("ngsim", "\u2275");
+        html5Entities.put("nGt", "\u226B\u20D2");
+        html5Entities.put("ngt", "\u226F");
+        html5Entities.put("ngtr", "\u226F");
+        html5Entities.put("nGtv", "\u226B\u0338");
+        html5Entities.put("nharr", "\u21AE");
+        html5Entities.put("nhArr", "\u21CE");
+        html5Entities.put("nhpar", "\u2AF2");
+        html5Entities.put("ni", "\u220B");
+        html5Entities.put("nis", "\u22FC");
+        html5Entities.put("nisd", "\u22FA");
+        html5Entities.put("niv", "\u220B");
+        html5Entities.put("NJcy", "\u040A");
+        html5Entities.put("njcy", "\u045A");
+        html5Entities.put("nlarr", "\u219A");
+        html5Entities.put("nlArr", "\u21CD");
+        html5Entities.put("nldr", "\u2025");
+        html5Entities.put("nlE", "\u2266\u0338");
+        html5Entities.put("nle", "\u2270");
+        html5Entities.put("nleftarrow", "\u219A");
+        html5Entities.put("nLeftarrow", "\u21CD");
+        html5Entities.put("nleftrightarrow", "\u21AE");
+        html5Entities.put("nLeftrightarrow", "\u21CE");
+        html5Entities.put("nleq", "\u2270");
+        html5Entities.put("nleqq", "\u2266\u0338");
+        html5Entities.put("nleqslant", "\u2A7D\u0338");
+        html5Entities.put("nles", "\u2A7D\u0338");
+        html5Entities.put("nless", "\u226E");
+        html5Entities.put("nLl", "\u22D8\u0338");
+        html5Entities.put("nlsim", "\u2274");
+        html5Entities.put("nLt", "\u226A\u20D2");
+        html5Entities.put("nlt", "\u226E");
+        html5Entities.put("nltri", "\u22EA");
+        html5Entities.put("nltrie", "\u22EC");
+        html5Entities.put("nLtv", "\u226A\u0338");
+        html5Entities.put("nmid", "\u2224");
+        html5Entities.put("NoBreak", "\u2060");
+        html5Entities.put("NonBreakingSpace", "\u00A0");
+        html5Entities.put("nopf", "\uD835\uDD5F");
+        html5Entities.put("Nopf", "\u2115");
+        html5Entities.put("Not", "\u2AEC");
+        html5Entities.put("not", "\u00AC");
+        html5Entities.put("NotCongruent", "\u2262");
+        html5Entities.put("NotCupCap", "\u226D");
+        html5Entities.put("NotDoubleVerticalBar", "\u2226");
+        html5Entities.put("NotElement", "\u2209");
+        html5Entities.put("NotEqual", "\u2260");
+        html5Entities.put("NotEqualTilde", "\u2242\u0338");
+        html5Entities.put("NotExists", "\u2204");
+        html5Entities.put("NotGreater", "\u226F");
+        html5Entities.put("NotGreaterEqual", "\u2271");
+        html5Entities.put("NotGreaterFullEqual", "\u2267\u0338");
+        html5Entities.put("NotGreaterGreater", "\u226B\u0338");
+        html5Entities.put("NotGreaterLess", "\u2279");
+        html5Entities.put("NotGreaterSlantEqual", "\u2A7E\u0338");
+        html5Entities.put("NotGreaterTilde", "\u2275");
+        html5Entities.put("NotHumpDownHump", "\u224E\u0338");
+        html5Entities.put("NotHumpEqual", "\u224F\u0338");
+        html5Entities.put("notin", "\u2209");
+        html5Entities.put("notindot", "\u22F5\u0338");
+        html5Entities.put("notinE", "\u22F9\u0338");
+        html5Entities.put("notinva", "\u2209");
+        html5Entities.put("notinvb", "\u22F7");
+        html5Entities.put("notinvc", "\u22F6");
+        html5Entities.put("NotLeftTriangleBar", "\u29CF\u0338");
+        html5Entities.put("NotLeftTriangle", "\u22EA");
+        html5Entities.put("NotLeftTriangleEqual", "\u22EC");
+        html5Entities.put("NotLess", "\u226E");
+        html5Entities.put("NotLessEqual", "\u2270");
+        html5Entities.put("NotLessGreater", "\u2278");
+        html5Entities.put("NotLessLess", "\u226A\u0338");
+        html5Entities.put("NotLessSlantEqual", "\u2A7D\u0338");
+        html5Entities.put("NotLessTilde", "\u2274");
+        html5Entities.put("NotNestedGreaterGreater", "\u2AA2\u0338");
+        html5Entities.put("NotNestedLessLess", "\u2AA1\u0338");
+        html5Entities.put("notni", "\u220C");
+        html5Entities.put("notniva", "\u220C");
+        html5Entities.put("notnivb", "\u22FE");
+        html5Entities.put("notnivc", "\u22FD");
+        html5Entities.put("NotPrecedes", "\u2280");
+        html5Entities.put("NotPrecedesEqual", "\u2AAF\u0338");
+        html5Entities.put("NotPrecedesSlantEqual", "\u22E0");
+        html5Entities.put("NotReverseElement", "\u220C");
+        html5Entities.put("NotRightTriangleBar", "\u29D0\u0338");
+        html5Entities.put("NotRightTriangle", "\u22EB");
+        html5Entities.put("NotRightTriangleEqual", "\u22ED");
+        html5Entities.put("NotSquareSubset", "\u228F\u0338");
+        html5Entities.put("NotSquareSubsetEqual", "\u22E2");
+        html5Entities.put("NotSquareSuperset", "\u2290\u0338");
+        html5Entities.put("NotSquareSupersetEqual", "\u22E3");
+        html5Entities.put("NotSubset", "\u2282\u20D2");
+        html5Entities.put("NotSubsetEqual", "\u2288");
+        html5Entities.put("NotSucceeds", "\u2281");
+        html5Entities.put("NotSucceedsEqual", "\u2AB0\u0338");
+        html5Entities.put("NotSucceedsSlantEqual", "\u22E1");
+        html5Entities.put("NotSucceedsTilde", "\u227F\u0338");
+        html5Entities.put("NotSuperset", "\u2283\u20D2");
+        html5Entities.put("NotSupersetEqual", "\u2289");
+        html5Entities.put("NotTilde", "\u2241");
+        html5Entities.put("NotTildeEqual", "\u2244");
+        html5Entities.put("NotTildeFullEqual", "\u2247");
+        html5Entities.put("NotTildeTilde", "\u2249");
+        html5Entities.put("NotVerticalBar", "\u2224");
+        html5Entities.put("nparallel", "\u2226");
+        html5Entities.put("npar", "\u2226");
+        html5Entities.put("nparsl", "\u2AFD\u20E5");
+        html5Entities.put("npart", "\u2202\u0338");
+        html5Entities.put("npolint", "\u2A14");
+        html5Entities.put("npr", "\u2280");
+        html5Entities.put("nprcue", "\u22E0");
+        html5Entities.put("nprec", "\u2280");
+        html5Entities.put("npreceq", "\u2AAF\u0338");
+        html5Entities.put("npre", "\u2AAF\u0338");
+        html5Entities.put("nrarrc", "\u2933\u0338");
+        html5Entities.put("nrarr", "\u219B");
+        html5Entities.put("nrArr", "\u21CF");
+        html5Entities.put("nrarrw", "\u219D\u0338");
+        html5Entities.put("nrightarrow", "\u219B");
+        html5Entities.put("nRightarrow", "\u21CF");
+        html5Entities.put("nrtri", "\u22EB");
+        html5Entities.put("nrtrie", "\u22ED");
+        html5Entities.put("nsc", "\u2281");
+        html5Entities.put("nsccue", "\u22E1");
+        html5Entities.put("nsce", "\u2AB0\u0338");
+        html5Entities.put("Nscr", "\uD835\uDCA9");
+        html5Entities.put("nscr", "\uD835\uDCC3");
+        html5Entities.put("nshortmid", "\u2224");
+        html5Entities.put("nshortparallel", "\u2226");
+        html5Entities.put("nsim", "\u2241");
+        html5Entities.put("nsime", "\u2244");
+        html5Entities.put("nsimeq", "\u2244");
+        html5Entities.put("nsmid", "\u2224");
+        html5Entities.put("nspar", "\u2226");
+        html5Entities.put("nsqsube", "\u22E2");
+        html5Entities.put("nsqsupe", "\u22E3");
+        html5Entities.put("nsub", "\u2284");
+        html5Entities.put("nsubE", "\u2AC5\u0338");
+        html5Entities.put("nsube", "\u2288");
+        html5Entities.put("nsubset", "\u2282\u20D2");
+        html5Entities.put("nsubseteq", "\u2288");
+        html5Entities.put("nsubseteqq", "\u2AC5\u0338");
+        html5Entities.put("nsucc", "\u2281");
+        html5Entities.put("nsucceq", "\u2AB0\u0338");
+        html5Entities.put("nsup", "\u2285");
+        html5Entities.put("nsupE", "\u2AC6\u0338");
+        html5Entities.put("nsupe", "\u2289");
+        html5Entities.put("nsupset", "\u2283\u20D2");
+        html5Entities.put("nsupseteq", "\u2289");
+        html5Entities.put("nsupseteqq", "\u2AC6\u0338");
+        html5Entities.put("ntgl", "\u2279");
+        html5Entities.put("Ntilde", "\u00D1");
+        html5Entities.put("ntilde", "\u00F1");
+        html5Entities.put("ntlg", "\u2278");
+        html5Entities.put("ntriangleleft", "\u22EA");
+        html5Entities.put("ntrianglelefteq", "\u22EC");
+        html5Entities.put("ntriangleright", "\u22EB");
+        html5Entities.put("ntrianglerighteq", "\u22ED");
+        html5Entities.put("Nu", "\u039D");
+        html5Entities.put("nu", "\u03BD");
+        html5Entities.put("num", "\u0023");
+        html5Entities.put("numero", "\u2116");
+        html5Entities.put("numsp", "\u2007");
+        html5Entities.put("nvap", "\u224D\u20D2");
+        html5Entities.put("nvdash", "\u22AC");
+        html5Entities.put("nvDash", "\u22AD");
+        html5Entities.put("nVdash", "\u22AE");
+        html5Entities.put("nVDash", "\u22AF");
+        html5Entities.put("nvge", "\u2265\u20D2");
+        html5Entities.put("nvgt", "\u003E\u20D2");
+        html5Entities.put("nvHarr", "\u2904");
+        html5Entities.put("nvinfin", "\u29DE");
+        html5Entities.put("nvlArr", "\u2902");
+        html5Entities.put("nvle", "\u2264\u20D2");
+        html5Entities.put("nvlt", "\u003C\u20D2");
+        html5Entities.put("nvltrie", "\u22B4\u20D2");
+        html5Entities.put("nvrArr", "\u2903");
+        html5Entities.put("nvrtrie", "\u22B5\u20D2");
+        html5Entities.put("nvsim", "\u223C\u20D2");
+        html5Entities.put("nwarhk", "\u2923");
+        html5Entities.put("nwarr", "\u2196");
+        html5Entities.put("nwArr", "\u21D6");
+        html5Entities.put("nwarrow", "\u2196");
+        html5Entities.put("nwnear", "\u2927");
+        html5Entities.put("Oacute", "\u00D3");
+        html5Entities.put("oacute", "\u00F3");
+        html5Entities.put("oast", "\u229B");
+        html5Entities.put("Ocirc", "\u00D4");
+        html5Entities.put("ocirc", "\u00F4");
+        html5Entities.put("ocir", "\u229A");
+        html5Entities.put("Ocy", "\u041E");
+        html5Entities.put("ocy", "\u043E");
+        html5Entities.put("odash", "\u229D");
+        html5Entities.put("Odblac", "\u0150");
+        html5Entities.put("odblac", "\u0151");
+        html5Entities.put("odiv", "\u2A38");
+        html5Entities.put("odot", "\u2299");
+        html5Entities.put("odsold", "\u29BC");
+        html5Entities.put("OElig", "\u0152");
+        html5Entities.put("oelig", "\u0153");
+        html5Entities.put("ofcir", "\u29BF");
+        html5Entities.put("Ofr", "\uD835\uDD12");
+        html5Entities.put("ofr", "\uD835\uDD2C");
+        html5Entities.put("ogon", "\u02DB");
+        html5Entities.put("Ograve", "\u00D2");
+        html5Entities.put("ograve", "\u00F2");
+        html5Entities.put("ogt", "\u29C1");
+        html5Entities.put("ohbar", "\u29B5");
+        html5Entities.put("ohm", "\u03A9");
+        html5Entities.put("oint", "\u222E");
+        html5Entities.put("olarr", "\u21BA");
+        html5Entities.put("olcir", "\u29BE");
+        html5Entities.put("olcross", "\u29BB");
+        html5Entities.put("oline", "\u203E");
+        html5Entities.put("olt", "\u29C0");
+        html5Entities.put("Omacr", "\u014C");
+        html5Entities.put("omacr", "\u014D");
+        html5Entities.put("Omega", "\u03A9");
+        html5Entities.put("omega", "\u03C9");
+        html5Entities.put("Omicron", "\u039F");
+        html5Entities.put("omicron", "\u03BF");
+        html5Entities.put("omid", "\u29B6");
+        html5Entities.put("ominus", "\u2296");
+        html5Entities.put("Oopf", "\uD835\uDD46");
+        html5Entities.put("oopf", "\uD835\uDD60");
+        html5Entities.put("opar", "\u29B7");
+        html5Entities.put("OpenCurlyDoubleQuote", "\u201C");
+        html5Entities.put("OpenCurlyQuote", "\u2018");
+        html5Entities.put("operp", "\u29B9");
+        html5Entities.put("oplus", "\u2295");
+        html5Entities.put("orarr", "\u21BB");
+        html5Entities.put("Or", "\u2A54");
+        html5Entities.put("or", "\u2228");
+        html5Entities.put("ord", "\u2A5D");
+        html5Entities.put("order", "\u2134");
+        html5Entities.put("orderof", "\u2134");
+        html5Entities.put("ordf", "\u00AA");
+        html5Entities.put("ordm", "\u00BA");
+        html5Entities.put("origof", "\u22B6");
+        html5Entities.put("oror", "\u2A56");
+        html5Entities.put("orslope", "\u2A57");
+        html5Entities.put("orv", "\u2A5B");
+        html5Entities.put("oS", "\u24C8");
+        html5Entities.put("Oscr", "\uD835\uDCAA");
+        html5Entities.put("oscr", "\u2134");
+        html5Entities.put("Oslash", "\u00D8");
+        html5Entities.put("oslash", "\u00F8");
+        html5Entities.put("osol", "\u2298");
+        html5Entities.put("Otilde", "\u00D5");
+        html5Entities.put("otilde", "\u00F5");
+        html5Entities.put("otimesas", "\u2A36");
+        html5Entities.put("Otimes", "\u2A37");
+        html5Entities.put("otimes", "\u2297");
+        html5Entities.put("Ouml", "\u00D6");
+        html5Entities.put("ouml", "\u00F6");
+        html5Entities.put("ovbar", "\u233D");
+        html5Entities.put("OverBar", "\u203E");
+        html5Entities.put("OverBrace", "\u23DE");
+        html5Entities.put("OverBracket", "\u23B4");
+        html5Entities.put("OverParenthesis", "\u23DC");
+        html5Entities.put("para", "\u00B6");
+        html5Entities.put("parallel", "\u2225");
+        html5Entities.put("par", "\u2225");
+        html5Entities.put("parsim", "\u2AF3");
+        html5Entities.put("parsl", "\u2AFD");
+        html5Entities.put("part", "\u2202");
+        html5Entities.put("PartialD", "\u2202");
+        html5Entities.put("Pcy", "\u041F");
+        html5Entities.put("pcy", "\u043F");
+        html5Entities.put("percnt", "\u0025");
+        html5Entities.put("period", "\u002E");
+        html5Entities.put("permil", "\u2030");
+        html5Entities.put("perp", "\u22A5");
+        html5Entities.put("pertenk", "\u2031");
+        html5Entities.put("Pfr", "\uD835\uDD13");
+        html5Entities.put("pfr", "\uD835\uDD2D");
+        html5Entities.put("Phi", "\u03A6");
+        html5Entities.put("phi", "\u03C6");
+        html5Entities.put("phiv", "\u03D5");
+        html5Entities.put("phmmat", "\u2133");
+        html5Entities.put("phone", "\u260E");
+        html5Entities.put("Pi", "\u03A0");
+        html5Entities.put("pi", "\u03C0");
+        html5Entities.put("pitchfork", "\u22D4");
+        html5Entities.put("piv", "\u03D6");
+        html5Entities.put("planck", "\u210F");
+        html5Entities.put("planckh", "\u210E");
+        html5Entities.put("plankv", "\u210F");
+        html5Entities.put("plusacir", "\u2A23");
+        html5Entities.put("plusb", "\u229E");
+        html5Entities.put("pluscir", "\u2A22");
+        html5Entities.put("plus", "\u002B");
+        html5Entities.put("plusdo", "\u2214");
+        html5Entities.put("plusdu", "\u2A25");
+        html5Entities.put("pluse", "\u2A72");
+        html5Entities.put("PlusMinus", "\u00B1");
+        html5Entities.put("plusmn", "\u00B1");
+        html5Entities.put("plussim", "\u2A26");
+        html5Entities.put("plustwo", "\u2A27");
+        html5Entities.put("pm", "\u00B1");
+        html5Entities.put("Poincareplane", "\u210C");
+        html5Entities.put("pointint", "\u2A15");
+        html5Entities.put("popf", "\uD835\uDD61");
+        html5Entities.put("Popf", "\u2119");
+        html5Entities.put("pound", "\u00A3");
+        html5Entities.put("prap", "\u2AB7");
+        html5Entities.put("Pr", "\u2ABB");
+        html5Entities.put("pr", "\u227A");
+        html5Entities.put("prcue", "\u227C");
+        html5Entities.put("precapprox", "\u2AB7");
+        html5Entities.put("prec", "\u227A");
+        html5Entities.put("preccurlyeq", "\u227C");
+        html5Entities.put("Precedes", "\u227A");
+        html5Entities.put("PrecedesEqual", "\u2AAF");
+        html5Entities.put("PrecedesSlantEqual", "\u227C");
+        html5Entities.put("PrecedesTilde", "\u227E");
+        html5Entities.put("preceq", "\u2AAF");
+        html5Entities.put("precnapprox", "\u2AB9");
+        html5Entities.put("precneqq", "\u2AB5");
+        html5Entities.put("precnsim", "\u22E8");
+        html5Entities.put("pre", "\u2AAF");
+        html5Entities.put("prE", "\u2AB3");
+        html5Entities.put("precsim", "\u227E");
+        html5Entities.put("prime", "\u2032");
+        html5Entities.put("Prime", "\u2033");
+        html5Entities.put("primes", "\u2119");
+        html5Entities.put("prnap", "\u2AB9");
+        html5Entities.put("prnE", "\u2AB5");
+        html5Entities.put("prnsim", "\u22E8");
+        html5Entities.put("prod", "\u220F");
+        html5Entities.put("Product", "\u220F");
+        html5Entities.put("profalar", "\u232E");
+        html5Entities.put("profline", "\u2312");
+        html5Entities.put("profsurf", "\u2313");
+        html5Entities.put("prop", "\u221D");
+        html5Entities.put("Proportional", "\u221D");
+        html5Entities.put("Proportion", "\u2237");
+        html5Entities.put("propto", "\u221D");
+        html5Entities.put("prsim", "\u227E");
+        html5Entities.put("prurel", "\u22B0");
+        html5Entities.put("Pscr", "\uD835\uDCAB");
+        html5Entities.put("pscr", "\uD835\uDCC5");
+        html5Entities.put("Psi", "\u03A8");
+        html5Entities.put("psi", "\u03C8");
+        html5Entities.put("puncsp", "\u2008");
+        html5Entities.put("Qfr", "\uD835\uDD14");
+        html5Entities.put("qfr", "\uD835\uDD2E");
+        html5Entities.put("qint", "\u2A0C");
+        html5Entities.put("qopf", "\uD835\uDD62");
+        html5Entities.put("Qopf", "\u211A");
+        html5Entities.put("qprime", "\u2057");
+        html5Entities.put("Qscr", "\uD835\uDCAC");
+        html5Entities.put("qscr", "\uD835\uDCC6");
+        html5Entities.put("quaternions", "\u210D");
+        html5Entities.put("quatint", "\u2A16");
+        html5Entities.put("quest", "\u003F");
+        html5Entities.put("questeq", "\u225F");
+        html5Entities.put("quot", "\"");
+        html5Entities.put("QUOT", "\"");
+        html5Entities.put("rAarr", "\u21DB");
+        html5Entities.put("race", "\u223D\u0331");
+        html5Entities.put("Racute", "\u0154");
+        html5Entities.put("racute", "\u0155");
+        html5Entities.put("radic", "\u221A");
+        html5Entities.put("raemptyv", "\u29B3");
+        html5Entities.put("rang", "\u27E9");
+        html5Entities.put("Rang", "\u27EB");
+        html5Entities.put("rangd", "\u2992");
+        html5Entities.put("range", "\u29A5");
+        html5Entities.put("rangle", "\u27E9");
+        html5Entities.put("raquo", "\u00BB");
+        html5Entities.put("rarrap", "\u2975");
+        html5Entities.put("rarrb", "\u21E5");
+        html5Entities.put("rarrbfs", "\u2920");
+        html5Entities.put("rarrc", "\u2933");
+        html5Entities.put("rarr", "\u2192");
+        html5Entities.put("Rarr", "\u21A0");
+        html5Entities.put("rArr", "\u21D2");
+        html5Entities.put("rarrfs", "\u291E");
+        html5Entities.put("rarrhk", "\u21AA");
+        html5Entities.put("rarrlp", "\u21AC");
+        html5Entities.put("rarrpl", "\u2945");
+        html5Entities.put("rarrsim", "\u2974");
+        html5Entities.put("Rarrtl", "\u2916");
+        html5Entities.put("rarrtl", "\u21A3");
+        html5Entities.put("rarrw", "\u219D");
+        html5Entities.put("ratail", "\u291A");
+        html5Entities.put("rAtail", "\u291C");
+        html5Entities.put("ratio", "\u2236");
+        html5Entities.put("rationals", "\u211A");
+        html5Entities.put("rbarr", "\u290D");
+        html5Entities.put("rBarr", "\u290F");
+        html5Entities.put("RBarr", "\u2910");
+        html5Entities.put("rbbrk", "\u2773");
+        html5Entities.put("rbrace", "\u007D");
+        html5Entities.put("rbrack", "\u005D");
+        html5Entities.put("rbrke", "\u298C");
+        html5Entities.put("rbrksld", "\u298E");
+        html5Entities.put("rbrkslu", "\u2990");
+        html5Entities.put("Rcaron", "\u0158");
+        html5Entities.put("rcaron", "\u0159");
+        html5Entities.put("Rcedil", "\u0156");
+        html5Entities.put("rcedil", "\u0157");
+        html5Entities.put("rceil", "\u2309");
+        html5Entities.put("rcub", "\u007D");
+        html5Entities.put("Rcy", "\u0420");
+        html5Entities.put("rcy", "\u0440");
+        html5Entities.put("rdca", "\u2937");
+        html5Entities.put("rdldhar", "\u2969");
+        html5Entities.put("rdquo", "\u201D");
+        html5Entities.put("rdquor", "\u201D");
+        html5Entities.put("rdsh", "\u21B3");
+        html5Entities.put("real", "\u211C");
+        html5Entities.put("realine", "\u211B");
+        html5Entities.put("realpart", "\u211C");
+        html5Entities.put("reals", "\u211D");
+        html5Entities.put("Re", "\u211C");
+        html5Entities.put("rect", "\u25AD");
+        html5Entities.put("reg", "\u00AE");
+        html5Entities.put("REG", "\u00AE");
+        html5Entities.put("ReverseElement", "\u220B");
+        html5Entities.put("ReverseEquilibrium", "\u21CB");
+        html5Entities.put("ReverseUpEquilibrium", "\u296F");
+        html5Entities.put("rfisht", "\u297D");
+        html5Entities.put("rfloor", "\u230B");
+        html5Entities.put("rfr", "\uD835\uDD2F");
+        html5Entities.put("Rfr", "\u211C");
+        html5Entities.put("rHar", "\u2964");
+        html5Entities.put("rhard", "\u21C1");
+        html5Entities.put("rharu", "\u21C0");
+        html5Entities.put("rharul", "\u296C");
+        html5Entities.put("Rho", "\u03A1");
+        html5Entities.put("rho", "\u03C1");
+        html5Entities.put("rhov", "\u03F1");
+        html5Entities.put("RightAngleBracket", "\u27E9");
+        html5Entities.put("RightArrowBar", "\u21E5");
+        html5Entities.put("rightarrow", "\u2192");
+        html5Entities.put("RightArrow", "\u2192");
+        html5Entities.put("Rightarrow", "\u21D2");
+        html5Entities.put("RightArrowLeftArrow", "\u21C4");
+        html5Entities.put("rightarrowtail", "\u21A3");
+        html5Entities.put("RightCeiling", "\u2309");
+        html5Entities.put("RightDoubleBracket", "\u27E7");
+        html5Entities.put("RightDownTeeVector", "\u295D");
+        html5Entities.put("RightDownVectorBar", "\u2955");
+        html5Entities.put("RightDownVector", "\u21C2");
+        html5Entities.put("RightFloor", "\u230B");
+        html5Entities.put("rightharpoondown", "\u21C1");
+        html5Entities.put("rightharpoonup", "\u21C0");
+        html5Entities.put("rightleftarrows", "\u21C4");
+        html5Entities.put("rightleftharpoons", "\u21CC");
+        html5Entities.put("rightrightarrows", "\u21C9");
+        html5Entities.put("rightsquigarrow", "\u219D");
+        html5Entities.put("RightTeeArrow", "\u21A6");
+        html5Entities.put("RightTee", "\u22A2");
+        html5Entities.put("RightTeeVector", "\u295B");
+        html5Entities.put("rightthreetimes", "\u22CC");
+        html5Entities.put("RightTriangleBar", "\u29D0");
+        html5Entities.put("RightTriangle", "\u22B3");
+        html5Entities.put("RightTriangleEqual", "\u22B5");
+        html5Entities.put("RightUpDownVector", "\u294F");
+        html5Entities.put("RightUpTeeVector", "\u295C");
+        html5Entities.put("RightUpVectorBar", "\u2954");
+        html5Entities.put("RightUpVector", "\u21BE");
+        html5Entities.put("RightVectorBar", "\u2953");
+        html5Entities.put("RightVector", "\u21C0");
+        html5Entities.put("ring", "\u02DA");
+        html5Entities.put("risingdotseq", "\u2253");
+        html5Entities.put("rlarr", "\u21C4");
+        html5Entities.put("rlhar", "\u21CC");
+        html5Entities.put("rlm", "\u200F");
+        html5Entities.put("rmoustache", "\u23B1");
+        html5Entities.put("rmoust", "\u23B1");
+        html5Entities.put("rnmid", "\u2AEE");
+        html5Entities.put("roang", "\u27ED");
+        html5Entities.put("roarr", "\u21FE");
+        html5Entities.put("robrk", "\u27E7");
+        html5Entities.put("ropar", "\u2986");
+        html5Entities.put("ropf", "\uD835\uDD63");
+        html5Entities.put("Ropf", "\u211D");
+        html5Entities.put("roplus", "\u2A2E");
+        html5Entities.put("rotimes", "\u2A35");
+        html5Entities.put("RoundImplies", "\u2970");
+        html5Entities.put("rpar", "\u0029");
+        html5Entities.put("rpargt", "\u2994");
+        html5Entities.put("rppolint", "\u2A12");
+        html5Entities.put("rrarr", "\u21C9");
+        html5Entities.put("Rrightarrow", "\u21DB");
+        html5Entities.put("rsaquo", "\u203A");
+        html5Entities.put("rscr", "\uD835\uDCC7");
+        html5Entities.put("Rscr", "\u211B");
+        html5Entities.put("rsh", "\u21B1");
+        html5Entities.put("Rsh", "\u21B1");
+        html5Entities.put("rsqb", "\u005D");
+        html5Entities.put("rsquo", "\u2019");
+        html5Entities.put("rsquor", "\u2019");
+        html5Entities.put("rthree", "\u22CC");
+        html5Entities.put("rtimes", "\u22CA");
+        html5Entities.put("rtri", "\u25B9");
+        html5Entities.put("rtrie", "\u22B5");
+        html5Entities.put("rtrif", "\u25B8");
+        html5Entities.put("rtriltri", "\u29CE");
+        html5Entities.put("RuleDelayed", "\u29F4");
+        html5Entities.put("ruluhar", "\u2968");
+        html5Entities.put("rx", "\u211E");
+        html5Entities.put("Sacute", "\u015A");
+        html5Entities.put("sacute", "\u015B");
+        html5Entities.put("sbquo", "\u201A");
+        html5Entities.put("scap", "\u2AB8");
+        html5Entities.put("Scaron", "\u0160");
+        html5Entities.put("scaron", "\u0161");
+        html5Entities.put("Sc", "\u2ABC");
+        html5Entities.put("sc", "\u227B");
+        html5Entities.put("sccue", "\u227D");
+        html5Entities.put("sce", "\u2AB0");
+        html5Entities.put("scE", "\u2AB4");
+        html5Entities.put("Scedil", "\u015E");
+        html5Entities.put("scedil", "\u015F");
+        html5Entities.put("Scirc", "\u015C");
+        html5Entities.put("scirc", "\u015D");
+        html5Entities.put("scnap", "\u2ABA");
+        html5Entities.put("scnE", "\u2AB6");
+        html5Entities.put("scnsim", "\u22E9");
+        html5Entities.put("scpolint", "\u2A13");
+        html5Entities.put("scsim", "\u227F");
+        html5Entities.put("Scy", "\u0421");
+        html5Entities.put("scy", "\u0441");
+        html5Entities.put("sdotb", "\u22A1");
+        html5Entities.put("sdot", "\u22C5");
+        html5Entities.put("sdote", "\u2A66");
+        html5Entities.put("searhk", "\u2925");
+        html5Entities.put("searr", "\u2198");
+        html5Entities.put("seArr", "\u21D8");
+        html5Entities.put("searrow", "\u2198");
+        html5Entities.put("sect", "\u00A7");
+        html5Entities.put("semi", "\u003B");
+        html5Entities.put("seswar", "\u2929");
+        html5Entities.put("setminus", "\u2216");
+        html5Entities.put("setmn", "\u2216");
+        html5Entities.put("sext", "\u2736");
+        html5Entities.put("Sfr", "\uD835\uDD16");
+        html5Entities.put("sfr", "\uD835\uDD30");
+        html5Entities.put("sfrown", "\u2322");
+        html5Entities.put("sharp", "\u266F");
+        html5Entities.put("SHCHcy", "\u0429");
+        html5Entities.put("shchcy", "\u0449");
+        html5Entities.put("SHcy", "\u0428");
+        html5Entities.put("shcy", "\u0448");
+        html5Entities.put("ShortDownArrow", "\u2193");
+        html5Entities.put("ShortLeftArrow", "\u2190");
+        html5Entities.put("shortmid", "\u2223");
+        html5Entities.put("shortparallel", "\u2225");
+        html5Entities.put("ShortRightArrow", "\u2192");
+        html5Entities.put("ShortUpArrow", "\u2191");
+        html5Entities.put("shy", "\u00AD");
+        html5Entities.put("Sigma", "\u03A3");
+        html5Entities.put("sigma", "\u03C3");
+        html5Entities.put("sigmaf", "\u03C2");
+        html5Entities.put("sigmav", "\u03C2");
+        html5Entities.put("sim", "\u223C");
+        html5Entities.put("simdot", "\u2A6A");
+        html5Entities.put("sime", "\u2243");
+        html5Entities.put("simeq", "\u2243");
+        html5Entities.put("simg", "\u2A9E");
+        html5Entities.put("simgE", "\u2AA0");
+        html5Entities.put("siml", "\u2A9D");
+        html5Entities.put("simlE", "\u2A9F");
+        html5Entities.put("simne", "\u2246");
+        html5Entities.put("simplus", "\u2A24");
+        html5Entities.put("simrarr", "\u2972");
+        html5Entities.put("slarr", "\u2190");
+        html5Entities.put("SmallCircle", "\u2218");
+        html5Entities.put("smallsetminus", "\u2216");
+        html5Entities.put("smashp", "\u2A33");
+        html5Entities.put("smeparsl", "\u29E4");
+        html5Entities.put("smid", "\u2223");
+        html5Entities.put("smile", "\u2323");
+        html5Entities.put("smt", "\u2AAA");
+        html5Entities.put("smte", "\u2AAC");
+        html5Entities.put("smtes", "\u2AAC\uFE00");
+        html5Entities.put("SOFTcy", "\u042C");
+        html5Entities.put("softcy", "\u044C");
+        html5Entities.put("solbar", "\u233F");
+        html5Entities.put("solb", "\u29C4");
+        html5Entities.put("sol", "\u002F");
+        html5Entities.put("Sopf", "\uD835\uDD4A");
+        html5Entities.put("sopf", "\uD835\uDD64");
+        html5Entities.put("spades", "\u2660");
+        html5Entities.put("spadesuit", "\u2660");
+        html5Entities.put("spar", "\u2225");
+        html5Entities.put("sqcap", "\u2293");
+        html5Entities.put("sqcaps", "\u2293\uFE00");
+        html5Entities.put("sqcup", "\u2294");
+        html5Entities.put("sqcups", "\u2294\uFE00");
+        html5Entities.put("Sqrt", "\u221A");
+        html5Entities.put("sqsub", "\u228F");
+        html5Entities.put("sqsube", "\u2291");
+        html5Entities.put("sqsubset", "\u228F");
+        html5Entities.put("sqsubseteq", "\u2291");
+        html5Entities.put("sqsup", "\u2290");
+        html5Entities.put("sqsupe", "\u2292");
+        html5Entities.put("sqsupset", "\u2290");
+        html5Entities.put("sqsupseteq", "\u2292");
+        html5Entities.put("square", "\u25A1");
+        html5Entities.put("Square", "\u25A1");
+        html5Entities.put("SquareIntersection", "\u2293");
+        html5Entities.put("SquareSubset", "\u228F");
+        html5Entities.put("SquareSubsetEqual", "\u2291");
+        html5Entities.put("SquareSuperset", "\u2290");
+        html5Entities.put("SquareSupersetEqual", "\u2292");
+        html5Entities.put("SquareUnion", "\u2294");
+        html5Entities.put("squarf", "\u25AA");
+        html5Entities.put("squ", "\u25A1");
+        html5Entities.put("squf", "\u25AA");
+        html5Entities.put("srarr", "\u2192");
+        html5Entities.put("Sscr", "\uD835\uDCAE");
+        html5Entities.put("sscr", "\uD835\uDCC8");
+        html5Entities.put("ssetmn", "\u2216");
+        html5Entities.put("ssmile", "\u2323");
+        html5Entities.put("sstarf", "\u22C6");
+        html5Entities.put("Star", "\u22C6");
+        html5Entities.put("star", "\u2606");
+        html5Entities.put("starf", "\u2605");
+        html5Entities.put("straightepsilon", "\u03F5");
+        html5Entities.put("straightphi", "\u03D5");
+        html5Entities.put("strns", "\u00AF");
+        html5Entities.put("sub", "\u2282");
+        html5Entities.put("Sub", "\u22D0");
+        html5Entities.put("subdot", "\u2ABD");
+        html5Entities.put("subE", "\u2AC5");
+        html5Entities.put("sube", "\u2286");
+        html5Entities.put("subedot", "\u2AC3");
+        html5Entities.put("submult", "\u2AC1");
+        html5Entities.put("subnE", "\u2ACB");
+        html5Entities.put("subne", "\u228A");
+        html5Entities.put("subplus", "\u2ABF");
+        html5Entities.put("subrarr", "\u2979");
+        html5Entities.put("subset", "\u2282");
+        html5Entities.put("Subset", "\u22D0");
+        html5Entities.put("subseteq", "\u2286");
+        html5Entities.put("subseteqq", "\u2AC5");
+        html5Entities.put("SubsetEqual", "\u2286");
+        html5Entities.put("subsetneq", "\u228A");
+        html5Entities.put("subsetneqq", "\u2ACB");
+        html5Entities.put("subsim", "\u2AC7");
+        html5Entities.put("subsub", "\u2AD5");
+        html5Entities.put("subsup", "\u2AD3");
+        html5Entities.put("succapprox", "\u2AB8");
+        html5Entities.put("succ", "\u227B");
+        html5Entities.put("succcurlyeq", "\u227D");
+        html5Entities.put("Succeeds", "\u227B");
+        html5Entities.put("SucceedsEqual", "\u2AB0");
+        html5Entities.put("SucceedsSlantEqual", "\u227D");
+        html5Entities.put("SucceedsTilde", "\u227F");
+        html5Entities.put("succeq", "\u2AB0");
+        html5Entities.put("succnapprox", "\u2ABA");
+        html5Entities.put("succneqq", "\u2AB6");
+        html5Entities.put("succnsim", "\u22E9");
+        html5Entities.put("succsim", "\u227F");
+        html5Entities.put("SuchThat", "\u220B");
+        html5Entities.put("sum", "\u2211");
+        html5Entities.put("Sum", "\u2211");
+        html5Entities.put("sung", "\u266A");
+        html5Entities.put("sup1", "\u00B9");
+        html5Entities.put("sup2", "\u00B2");
+        html5Entities.put("sup3", "\u00B3");
+        html5Entities.put("sup", "\u2283");
+        html5Entities.put("Sup", "\u22D1");
+        html5Entities.put("supdot", "\u2ABE");
+        html5Entities.put("supdsub", "\u2AD8");
+        html5Entities.put("supE", "\u2AC6");
+        html5Entities.put("supe", "\u2287");
+        html5Entities.put("supedot", "\u2AC4");
+        html5Entities.put("Superset", "\u2283");
+        html5Entities.put("SupersetEqual", "\u2287");
+        html5Entities.put("suphsol", "\u27C9");
+        html5Entities.put("suphsub", "\u2AD7");
+        html5Entities.put("suplarr", "\u297B");
+        html5Entities.put("supmult", "\u2AC2");
+        html5Entities.put("supnE", "\u2ACC");