Merge
authormseledtsov
Fri, 08 Mar 2019 11:09:39 -0800
changeset 54038 2915818a0237
parent 54037 e693e12250d3 (current diff)
parent 54036 c70747878f6f (diff)
child 54039 fd6c13481231
Merge
--- a/src/hotspot/os/posix/os_posix.cpp	Fri Mar 08 11:08:11 2019 -0800
+++ b/src/hotspot/os/posix/os_posix.cpp	Fri Mar 08 11:09:39 2019 -0800
@@ -31,6 +31,7 @@
 #include "runtime/interfaceSupport.inline.hpp"
 #include "services/memTracker.hpp"
 #include "utilities/align.hpp"
+#include "utilities/events.hpp"
 #include "utilities/formatBuffer.hpp"
 #include "utilities/macros.hpp"
 #include "utilities/vmError.hpp"
@@ -1269,6 +1270,15 @@
   return true;
 }
 
+bool os::signal_sent_by_kill(const void* siginfo) {
+  const siginfo_t* const si = (const siginfo_t*)siginfo;
+  return si->si_code == SI_USER || si->si_code == SI_QUEUE
+#ifdef SI_TKILL
+         || si->si_code == SI_TKILL
+#endif
+  ;
+}
+
 void os::print_siginfo(outputStream* os, const void* si0) {
 
   const siginfo_t* const si = (const siginfo_t*) si0;
@@ -1299,7 +1309,7 @@
   // so it depends on the context which member to use. For synchronous error signals,
   // we print si_addr, unless the signal was sent by another process or thread, in
   // which case we print out pid or tid of the sender.
-  if (si->si_code == SI_USER || si->si_code == SI_QUEUE) {
+  if (signal_sent_by_kill(si)) {
     const pid_t pid = si->si_pid;
     os->print(", si_pid: %ld", (long) pid);
     if (IS_VALID_PID(pid)) {
@@ -1325,6 +1335,25 @@
 
 }
 
+bool os::signal_thread(Thread* thread, int sig, const char* reason) {
+  OSThread* osthread = thread->osthread();
+  if (osthread) {
+#if defined (SOLARIS)
+    // Note: we cannot use pthread_kill on Solaris - not because
+    // its missing, but because we do not have the pthread_t id.
+    int status = thr_kill(osthread->thread_id(), sig);
+#else
+    int status = pthread_kill(osthread->pthread_id(), sig);
+#endif
+    if (status == 0) {
+      Events::log(Thread::current(), "sent signal %d to Thread " INTPTR_FORMAT " because %s.",
+                  sig, p2i(thread), reason);
+      return true;
+    }
+  }
+  return false;
+}
+
 int os::Posix::unblock_thread_signal_mask(const sigset_t *set) {
   return pthread_sigmask(SIG_UNBLOCK, set, NULL);
 }
--- a/src/hotspot/os/windows/os_windows.cpp	Fri Mar 08 11:08:11 2019 -0800
+++ b/src/hotspot/os/windows/os_windows.cpp	Fri Mar 08 11:09:39 2019 -0800
@@ -1797,6 +1797,11 @@
   st->cr();
 }
 
+bool os::signal_sent_by_kill(const void* siginfo) {
+  // TODO: Is this possible?
+  return false;
+}
+
 void os::print_siginfo(outputStream *st, const void* siginfo) {
   const EXCEPTION_RECORD* const er = (EXCEPTION_RECORD*)siginfo;
   st->print("siginfo:");
@@ -1830,6 +1835,11 @@
   st->cr();
 }
 
+bool os::signal_thread(Thread* thread, int sig, const char* reason) {
+  // TODO: Can we kill thread?
+  return false;
+}
+
 void os::print_signal_handlers(outputStream* st, char* buf, size_t buflen) {
   // do nothing
 }
--- a/src/hotspot/share/ci/ciReplay.cpp	Fri Mar 08 11:08:11 2019 -0800
+++ b/src/hotspot/share/ci/ciReplay.cpp	Fri Mar 08 11:09:39 2019 -0800
@@ -274,15 +274,42 @@
   // Parse a sequence of raw data encoded as bytes and return the
   // resulting data.
   char* parse_data(const char* tag, int& length) {
-    if (!parse_tag_and_count(tag, length)) {
+    int read_size = 0;
+    if (!parse_tag_and_count(tag, read_size)) {
       return NULL;
     }
 
-    char * result = NEW_RESOURCE_ARRAY(char, length);
-    for (int i = 0; i < length; i++) {
+    int actual_size = sizeof(MethodData);
+    char *result = NEW_RESOURCE_ARRAY(char, actual_size);
+    int i = 0;
+    if (read_size != actual_size) {
+      tty->print_cr("Warning: ciMethodData parsing sees MethodData size %i in file, current is %i", read_size,
+                    actual_size);
+      // Replay serializes the entire MethodData, but the data is at the end.
+      // If the MethodData instance size has changed, we can pad or truncate in the beginning
+      int padding = actual_size - read_size;
+      if (padding > 0) {
+        // pad missing data with zeros
+        tty->print_cr("- Padding MethodData");
+        for (; i < padding; i++) {
+          result[i] = 0;
+        }
+      } else if (padding < 0) {
+        // drop some data
+        tty->print_cr("- Truncating MethodData");
+        for (int j = 0; j < -padding; j++) {
+          int val = parse_int("data");
+          // discard val
+        }
+      }
+    }
+
+    assert(i < actual_size, "At least some data must remain to be copied");
+    for (; i < actual_size; i++) {
       int val = parse_int("data");
       result[i] = val;
     }
+    length = actual_size;
     return result;
   }
 
--- a/src/hotspot/share/gc/shared/genCollectedHeap.cpp	Fri Mar 08 11:08:11 2019 -0800
+++ b/src/hotspot/share/gc/shared/genCollectedHeap.cpp	Fri Mar 08 11:09:39 2019 -0800
@@ -679,7 +679,9 @@
     // Track memory usage and detect low memory after GC finishes
     MemoryService::track_memory_usage();
 
-    gc_epilogue(complete);
+    // Need to tell the epilogue code we are done with Full GC, regardless what was
+    // the initial value for "complete" flag.
+    gc_epilogue(true);
 
     BiasedLocking::restore_marks();
 
--- a/src/hotspot/share/runtime/globals.hpp	Fri Mar 08 11:08:11 2019 -0800
+++ b/src/hotspot/share/runtime/globals.hpp	Fri Mar 08 11:09:39 2019 -0800
@@ -367,7 +367,7 @@
           "Print out every time compilation is longer than "                \
           "a given threshold")                                              \
                                                                             \
-  develop(bool, SafepointALot, false,                                       \
+  diagnostic(bool, SafepointALot, false,                                    \
           "Generate a lot of safepoints. This works with "                  \
           "GuaranteedSafepointInterval")                                    \
                                                                             \
--- a/src/hotspot/share/runtime/handshake.cpp	Fri Mar 08 11:08:11 2019 -0800
+++ b/src/hotspot/share/runtime/handshake.cpp	Fri Mar 08 11:09:39 2019 -0800
@@ -288,13 +288,14 @@
   assert(Thread::current() == thread, "should call from thread");
   assert(!thread->is_terminated(), "should not be a terminated thread");
 
-  CautiouslyPreserveExceptionMark pem(thread);
   ThreadInVMForHandshake tivm(thread);
   if (!_semaphore.trywait()) {
     _semaphore.wait_with_safepoint_check(thread);
   }
   HandshakeOperation* op = OrderAccess::load_acquire(&_operation);
   if (op != NULL) {
+    HandleMark hm(thread);
+    CautiouslyPreserveExceptionMark pem(thread);
     // Disarm before execute the operation
     clear_handshake(thread);
     op->do_handshake(thread);
--- a/src/hotspot/share/runtime/os.hpp	Fri Mar 08 11:08:11 2019 -0800
+++ b/src/hotspot/share/runtime/os.hpp	Fri Mar 08 11:09:39 2019 -0800
@@ -463,6 +463,9 @@
   static void pd_start_thread(Thread* thread);
   static void start_thread(Thread* thread);
 
+  // Returns true if successful.
+  static bool signal_thread(Thread* thread, int sig, const char* reason);
+
   static void free_thread(OSThread* osthread);
 
   // thread id on Linux/64bit is 64bit, on Windows and Solaris, it's 32bit
@@ -637,6 +640,7 @@
   static void print_environment_variables(outputStream* st, const char** env_list);
   static void print_context(outputStream* st, const void* context);
   static void print_register_info(outputStream* st, const void* context);
+  static bool signal_sent_by_kill(const void* siginfo);
   static void print_siginfo(outputStream* st, const void* siginfo);
   static void print_signal_handlers(outputStream* st, char* buf, size_t buflen);
   static void print_date_and_time(outputStream* st, char* buf, size_t buflen);
--- a/src/hotspot/share/runtime/safepoint.cpp	Fri Mar 08 11:08:11 2019 -0800
+++ b/src/hotspot/share/runtime/safepoint.cpp	Fri Mar 08 11:09:39 2019 -0800
@@ -902,6 +902,16 @@
   // To debug the long safepoint, specify both AbortVMOnSafepointTimeout &
   // ShowMessageBoxOnError.
   if (AbortVMOnSafepointTimeout) {
+    // Send the blocking thread a signal to terminate and write an error file.
+    for (JavaThreadIteratorWithHandle jtiwh; JavaThread *cur_thread = jtiwh.next(); ) {
+      if (cur_thread->safepoint_state()->is_running()) {
+        if (!os::signal_thread(cur_thread, SIGILL, "blocking a safepoint")) {
+          break; // Could not send signal. Report fatal error.
+        }
+        // Give cur_thread a chance to report the error and terminate the VM.
+        os::sleep(Thread::current(), 3000, false);
+      }
+    }
     fatal("Safepoint sync time longer than " INTX_FORMAT "ms detected when executing %s.",
           SafepointTimeoutDelay, VMThread::vm_operation()->name());
   }
--- a/src/hotspot/share/utilities/globalDefinitions_gcc.hpp	Fri Mar 08 11:08:11 2019 -0800
+++ b/src/hotspot/share/utilities/globalDefinitions_gcc.hpp	Fri Mar 08 11:09:39 2019 -0800
@@ -269,6 +269,9 @@
 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55382 and
 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53017
 //
-#define ATTRIBUTE_ALIGNED(x) __attribute__((aligned(x+0)))
+// GCC versions older than 4.6.4 would fail even with "+0", and needs additional
+// cast to typeof(x) to work around the similar bug.
+//
+#define ATTRIBUTE_ALIGNED(x) __attribute__((aligned((typeof(x))x+0)))
 
 #endif // SHARE_UTILITIES_GLOBALDEFINITIONS_GCC_HPP
--- a/src/hotspot/share/utilities/vmError.cpp	Fri Mar 08 11:08:11 2019 -0800
+++ b/src/hotspot/share/utilities/vmError.cpp	Fri Mar 08 11:09:39 2019 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -522,6 +522,9 @@
        st->print("%s", buf);
        st->print(" (0x%x)", _id);                // signal number
        st->print(" at pc=" PTR_FORMAT, p2i(_pc));
+       if (_siginfo != NULL && os::signal_sent_by_kill(_siginfo)) {
+         st->print(" (sent by kill)");
+       }
      } else {
        if (should_report_bug(_id)) {
          st->print("Internal Error");
--- a/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java	Fri Mar 08 11:08:11 2019 -0800
+++ b/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java	Fri Mar 08 11:09:39 2019 -0800
@@ -399,7 +399,6 @@
         if (len > TRIGGERLEN) {
             int i = 0;
             int tlen;  // incremental lengths
-            // 96bit CTR x86 intrinsic
             final int plen = AES_BLOCK_SIZE * 6;
             // arbitrary formula to aid intrinsic without reaching buffer end
             final int count = len / 1024;
@@ -419,11 +418,11 @@
         gctrPAndC.doFinal(in, inOfs, ilen, out, outOfs);
         processed += ilen;
 
-        int lastLen = len  % AES_BLOCK_SIZE;
+        int lastLen = ilen % AES_BLOCK_SIZE;
         if (lastLen != 0) {
-            ghashAllToS.update(ct, ctOfs, len - lastLen);
+            ghashAllToS.update(ct, ctOfs, ilen - lastLen);
             ghashAllToS.update(
-                    expandToOneBlock(ct, (ctOfs + len - lastLen), lastLen));
+                    expandToOneBlock(ct, (ctOfs + ilen - lastLen), lastLen));
         } else {
             ghashAllToS.update(ct, ctOfs, ilen);
         }
--- a/test/hotspot/jtreg/TEST.groups	Fri Mar 08 11:08:11 2019 -0800
+++ b/test/hotspot/jtreg/TEST.groups	Fri Mar 08 11:09:39 2019 -0800
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 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
@@ -265,6 +265,7 @@
  -runtime/7158988/FieldMonitor.java \
  -runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java \
  -runtime/CommandLine/PrintGCApplicationConcurrentTime.java \
+ -runtime/CompressedOops/UseCompressedOops.java \
  -runtime/ConstantPool/IntfMethod.java \
  -runtime/ErrorHandling/CreateCoredumpOnCrash.java \
  -runtime/ErrorHandling/ErrorHandler.java \
@@ -346,6 +347,7 @@
   runtime/ \
   serviceability/ \
  -runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java \
+ -runtime/CompressedOops/UseCompressedOops.java \
  -runtime/Thread/TestThreadDumpMonitorContention.java \
  -runtime/containers/ \
  -:tier1_runtime \
--- a/test/hotspot/jtreg/compiler/runtime/safepoints/TestRegisterRestoring.java	Fri Mar 08 11:08:11 2019 -0800
+++ b/test/hotspot/jtreg/compiler/runtime/safepoints/TestRegisterRestoring.java	Fri Mar 08 11:09:39 2019 -0800
@@ -26,8 +26,8 @@
  * @bug 8148490
  * @summary Test correct saving and restoring of vector registers at safepoints.
  *
- * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xbatch -XX:-TieredCompilation
- *                   -XX:+SafepointALot
+ * @run main/othervm -Xbatch -XX:-TieredCompilation
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+SafepointALot
  *                   -XX:CompileCommand=exclude,compiler.runtime.safepoints.TestRegisterRestoring::main
  *                   compiler.runtime.safepoints.TestRegisterRestoring
  */
--- a/test/hotspot/jtreg/runtime/CompressedOops/UseCompressedOops.java	Fri Mar 08 11:08:11 2019 -0800
+++ b/test/hotspot/jtreg/runtime/CompressedOops/UseCompressedOops.java	Fri Mar 08 11:09:39 2019 -0800
@@ -30,7 +30,7 @@
  *          java.management
  * @build sun.hotspot.WhiteBox
  * @run driver ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission
- * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. UseCompressedOops
+ * @run main/othervm/timeout=480 -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. UseCompressedOops
  */
 import java.util.ArrayList;
 import java.util.Collections;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/Safepoint/TestAbortVMOnSafepointTimeout.java	Fri Mar 08 11:09:39 2019 -0800
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import jdk.test.lib.*;
+import jdk.test.lib.process.*;
+
+/*
+ * @test TestAbortVMOnSafepointTimeout
+ * @summary Check if VM can kill thread which doesn't reach safepoint.
+ * @bug 8219584
+ * @requires vm.compiler2.enabled
+ * @library /test/lib
+ * @modules java.base/jdk.internal.misc
+ *          java.management
+ */
+
+public class TestAbortVMOnSafepointTimeout {
+
+    public static void main(String[] args) throws Exception {
+        if (args.length > 0) {
+            int result = test_loop(3);
+            System.out.println("This message would occur after some time with result " + result);
+            return;
+        }
+
+        testWith(500, 500);
+    }
+
+    static int test_loop(int x) {
+        int sum = 0;
+        if (x != 0) {
+            // Long running loop without safepoint.
+            for (int y = 1; y < Integer.MAX_VALUE; ++y) {
+                if (y % x == 0) ++sum;
+            }
+        }
+        return sum;
+    }
+
+    public static void testWith(int sfpt_interval, int timeout_delay) throws Exception {
+        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+                "-XX:+UnlockDiagnosticVMOptions",
+                "-XX:+SafepointTimeout",
+                "-XX:+SafepointALot",
+                "-XX:+AbortVMOnSafepointTimeout",
+                "-XX:SafepointTimeoutDelay=" + timeout_delay,
+                "-XX:GuaranteedSafepointInterval=" + sfpt_interval,
+                "-XX:-TieredCompilation",
+                "-XX:-UseCountedLoopSafepoints",
+                "-XX:LoopStripMiningIter=0",
+                "-XX:LoopUnrollLimit=0",
+                "-XX:CompileCommand=compileonly,TestAbortVMOnSafepointTimeout::test_loop",
+                "-Xcomp",
+                "-XX:-CreateCoredumpOnCrash",
+                "-Xms64m",
+                "TestAbortVMOnSafepointTimeout",
+                "runTestLoop"
+        );
+
+        OutputAnalyzer output = new OutputAnalyzer(pb.start());
+        if (Platform.isWindows()) {
+            output.shouldMatch("Safepoint sync time longer than");
+        } else {
+            output.shouldMatch("SIGILL");
+            if (Platform.isLinux()) {
+                output.shouldMatch("(sent by kill)");
+            }
+            output.shouldMatch("TestAbortVMOnSafepointTimeout.test_loop");
+        }
+        output.shouldNotHaveExitValue(0);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/com/sun/crypto/provider/Cipher/AEAD/GCMLargeDataKAT.java	Fri Mar 08 11:09:39 2019 -0800
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.GCMParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.security.MessageDigest;
+import java.util.HashMap;
+
+/*
+ * @test
+ * @bug 8220165
+ * @summary Verify correctness of large data sizes for GCM.
+ */
+
+/**
+ * This test stores the MD5 hash of correctly encrypted AES/GCM data for
+ * particular data lengths.  Those lengths are run on SunJCE to verify returns
+ * the same MD5 hash of the encrypted data.  These are not NIST data sets or
+ * provided by any other organization.  The data sets are known good values,
+ * verified with two different JCE providers (solaris-sparcv9 ucrypto and
+ * linux SunJCE).
+ *
+ * Lengths around 64k are chosen because 64k is the point where
+ * com.sun.crypto.provider.GaloisCounterMode#doLastBlock() starts it's
+ * intrinsic warmup
+ *
+ * Plaintext is all zeros.  Preset key and IV.
+ *
+ * The choice of MD5 is for speed.  Shortcoming of the algorithm are
+ * not relevant for this test.
+ */
+
+public class GCMLargeDataKAT {
+
+    // Hash of encrypted results of AES/GCM for particular lengths.
+    // <data size, hash>
+    static final HashMap<Integer, String> results = new HashMap<>() {{
+        put(65534, "1397b91c31ce793895edace4e175bfee");  //64k-2
+        put(65535, "4ad101c9f450e686668b3f8f05db96f0");  //64k-1
+        put(65536, "fbfaee3451acd3f603200d6be0f39b24");  //64k
+        put(65537, "e7dfca4a71495c65d20982c3c9b9813f");  //64k+1
+        put(67583, "c8ebdcb3532ec6c165de961341af7635");  //66k-1
+        put(67584, "36559d108dfd25dd29da3fec3455b9e5");  //66k
+        put(67585, "1d21b42d80ea179810744fc23dc228b6");  //66k+1
+        put(102400, "0d1544fcab20bbd4c8103b9d273f2c82"); //100k
+        put(102401, "f2d53ef65fd12d0a861368659b23ea2e"); //100k+1
+        put(102402, "97f0f524cf63d2d9d23d81e64d416ee0"); //100k+2
+        put(102403, "4a6b4af55b7d9016b64114d6813d639c"); //100k+3
+        put(102404, "ba63cc131fcde2f12ddf2ac634201be8"); //100k+4
+        put(102405, "673d05c7fe5e283e42e5c0d049fdcea6"); //100k+5
+        put(102406, "76cc99a7850ce857eb3cb43049cf9877"); //100k+6
+        put(102407, "65863f99072cf2eb7fce18bd78b33f4e"); //100k+7
+        put(102408, "b9184f0f272682cc1f791fa7070eddd4"); //100k+8
+        put(102409, "45fe36afef43cc665bf22a9ca200c3c2"); //100k+9
+        put(102410, "67249e41646edcb37a78a61b0743cf11"); //100k+0
+        put(102411, "ffdc611e29c8849842e81ec78f32c415"); //100k+11
+        put(102412, "b7fde7fd52221057dccc1c181a140125"); //100k+12
+        put(102413, "4b1d6c64d56448105e5613157e69c0ae"); //100k+13
+        put(102414, "6d2c0b26c0c8785c8eec3298a5f0080c"); //100k+14
+        put(102415, "1df2061b114fbe56bdf3717e3ee61ef9"); //100k+15
+        put(102416, "a691742692c683ac9d1254df5fc5f768"); //100k+16
+    }};
+    static final int HIGHLEN = 102416;
+
+    static final int GCM_TAG_LENGTH = 16;
+    static final byte[] iv = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
+    static final byte[] key_code = {
+            0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+    };
+    static final GCMParameterSpec spec =
+            new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv);
+    static final SecretKey key = new SecretKeySpec(key_code, "AES");
+    static boolean testresult = true;
+    static byte[] plaintext = new byte[HIGHLEN];
+    static MessageDigest md5;
+    Cipher cipher;
+
+    GCMLargeDataKAT() {
+    }
+
+    byte[] encrypt(int inLen) {
+        try {
+            cipher = Cipher.getInstance("AES/GCM/NoPadding", "SunJCE");
+            cipher.init(Cipher.ENCRYPT_MODE, key, spec);
+            return cipher.doFinal(plaintext, 0, inLen);
+        } catch (Exception e) {
+            System.err.println("Encrypt Failure (length = " + inLen + ") : " +
+                    e.getMessage());
+            e.printStackTrace();
+        }
+        return new byte[0];
+    }
+
+    static byte[] hash(byte[] data) {
+        return md5.digest(data);
+    }
+
+    // Decrypt the data and return a boolean if the plaintext is all 0's.
+    boolean decrypt(byte[] data) {
+        byte[] result = null;
+        int len = data.length - GCM_TAG_LENGTH;
+        if (data.length == 0) {
+            return false;
+        }
+        try {
+            cipher = Cipher.getInstance("AES/GCM/NoPadding", "SunJCE");
+            cipher.init(Cipher.DECRYPT_MODE, key, spec);
+            result = cipher.doFinal(data);
+        } catch (Exception e) {
+            System.err.println("Decrypt Failure (length = " + len + ") : " +
+                    e.getMessage());
+            e.printStackTrace();
+            return false;
+        }
+
+        if (result.length != len) {
+            System.err.println("Decrypt Failure (length = " + len +
+                    ") : plaintext length invalid = " + result.length);
+        }
+        // Return false if we find a non zero.
+        int i = 0;
+        while (result.length > i) {
+            if (result[i++] != 0) {
+                System.err.println("Decrypt Failure (length = " + len +
+                        ") : plaintext invalid, char index " + i);
+                return false;
+            }
+        }
+        return true;
+    }
+
+    void test() throws Exception {
+
+        // results order is not important
+        for (int l : results.keySet()) {
+            byte[] enc = new GCMLargeDataKAT().encrypt(l);
+
+            // verify hash with stored hash of that length
+            String hashstr = toHex(hash(enc));
+            boolean r = (hashstr.compareTo(results.get(l)) == 0);
+
+            System.out.println("---------------------------------------------");
+
+            // Encrypted test & results
+            System.out.println("Encrypt data size " + l + " \tResult: " +
+                    (r ? "Pass" : "Fail"));
+            if (!r) {
+                if (enc.length != 0) {
+                    System.out.println("\tExpected: " + results.get(l));
+                    System.out.println("\tReturned: " + hashstr);
+                }
+                testresult = false;
+                continue;
+            }
+
+            // Decrypted test & results
+            r = decrypt(enc);
+            System.out.println("Decrypt data size " + l + " \tResult: " +
+                    (r ? "Pass" : "Fail"));
+            if (!r) {
+                testresult = false;
+            }
+        }
+
+        // After test complete, throw an error if there was a failure
+        if (!testresult) {
+            throw new Exception("Tests failed");
+        }
+    }
+
+    /**
+     * With no argument, the test will run the predefined data lengths
+     *
+     * With an integer argument, this test will print the hash of the encrypted
+     * data of that integer length.
+     *
+     */
+    public static void main(String args[]) throws Exception {
+        md5 = MessageDigest.getInstance("MD5");
+
+        if (args.length > 0) {
+            int len = Integer.parseInt(args[0]);
+            byte[] e = new GCMLargeDataKAT().encrypt(len);
+            System.out.println(toHex(hash(e)));
+            return;
+        }
+
+        new GCMLargeDataKAT().test();
+    }
+
+    // bytes to hex string
+    static String toHex(byte[] bytes) {
+        StringBuffer hexStringBuffer = new StringBuffer(32);
+        for (int i = 0; i < bytes.length; i++) {
+            hexStringBuffer.append(byteToHex(bytes[i]));
+        }
+        return hexStringBuffer.toString();
+    }
+    // byte to hex
+    static String byteToHex(byte num) {
+        char[] hexDigits = new char[2];
+        hexDigits[0] = Character.forDigit((num >> 4) & 0xF, 16);
+        hexDigits[1] = Character.forDigit((num & 0xF), 16);
+        return new String(hexDigits);
+    }
+}