8260296: SA's dumpreplaydata fails

Reviewed-by: kvn, cjplummer, iignatyev
diff --git a/src/hotspot/share/ci/ciMetadata.cpp b/src/hotspot/share/ci/ciMetadata.cpp
index 9bffead..f0d1fcf 100644
--- a/src/hotspot/share/ci/ciMetadata.cpp
+++ b/src/hotspot/share/ci/ciMetadata.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2021, 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,6 +27,9 @@
 #include "ci/ciUtilities.inline.hpp"
 #include "gc/shared/collectedHeap.inline.hpp"
 
+// Not inlined to preserve visibility of ciMetaData vtable symbol. Required by SA.
+bool ciMetadata::is_classless() const { return false; }
+
 // ------------------------------------------------------------------
 // ciMetadata::print
 //
diff --git a/src/hotspot/share/ci/ciMetadata.hpp b/src/hotspot/share/ci/ciMetadata.hpp
index a0b7b38..dcf01b6 100644
--- a/src/hotspot/share/ci/ciMetadata.hpp
+++ b/src/hotspot/share/ci/ciMetadata.hpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2021, 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
@@ -43,7 +43,7 @@
   ciMetadata(): _metadata(NULL) {}
   ciMetadata(Metadata* o): _metadata(o) {}
 
-  virtual bool is_classless() const         { return false; }
+  virtual bool is_classless() const;
  public:
   bool is_loaded() const { return _metadata != NULL || is_classless(); }
 
diff --git a/src/hotspot/share/oops/methodData.cpp b/src/hotspot/share/oops/methodData.cpp
index b97bd21..54aa8ec 100644
--- a/src/hotspot/share/oops/methodData.cpp
+++ b/src/hotspot/share/oops/methodData.cpp
@@ -1256,7 +1256,7 @@
   object_size += extra_size + arg_data_size;
 
   int parms_cell = ParametersTypeData::compute_cell_count(method());
-  // If we are profiling parameters, we reserver an area near the end
+  // If we are profiling parameters, we reserved an area near the end
   // of the MDO after the slots for bytecodes (because there's no bci
   // for method entry so they don't fit with the framework for the
   // profiling of bytecodes). We store the offset within the MDO of
diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp
index 46c4811..f4741b1 100644
--- a/src/hotspot/share/runtime/vmStructs.cpp
+++ b/src/hotspot/share/runtime/vmStructs.cpp
@@ -261,7 +261,7 @@
   nonstatic_field(Klass,                       _java_mirror,                                  OopHandle)                             \
   nonstatic_field(Klass,                       _modifier_flags,                               jint)                                  \
   nonstatic_field(Klass,                       _super,                                        Klass*)                                \
-  volatile_nonstatic_field(Klass,              _subklass,                                     Klass*)                                 \
+  volatile_nonstatic_field(Klass,              _subklass,                                     Klass*)                                \
   nonstatic_field(Klass,                       _layout_helper,                                jint)                                  \
   nonstatic_field(Klass,                       _name,                                         Symbol*)                               \
   nonstatic_field(Klass,                       _access_flags,                                 AccessFlags)                           \
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciMethodData.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciMethodData.java
index 873d7f4..2bad7f9 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciMethodData.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ci/ciMethodData.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,6 +30,7 @@
 import sun.jvm.hotspot.runtime.*;
 import sun.jvm.hotspot.oops.*;
 import sun.jvm.hotspot.types.*;
+import sun.jvm.hotspot.types.Field;
 import sun.jvm.hotspot.utilities.Observable;
 import sun.jvm.hotspot.utilities.Observer;
 
@@ -44,7 +45,7 @@
 
   private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
     Type type      = db.lookupType("ciMethodData");
-    origField = type.getAddressField("_orig");
+    origField = type.getField("_orig");
     currentMileageField = new CIntField(type.getCIntegerField("_current_mileage"), 0);
     argReturnedField = new CIntField(type.getCIntegerField("_arg_returned"), 0);
     argStackField = new CIntField(type.getCIntegerField("_arg_stack"), 0);
@@ -61,7 +62,7 @@
     parametersTypeDataDi = new CIntField(typeMethodData.getCIntegerField("_parameters_type_data_di"), 0);
   }
 
-  private static AddressField origField;
+  private static Field origField;
   private static CIntField currentMileageField;
   private static CIntField argReturnedField;
   private static CIntField argStackField;
@@ -106,8 +107,8 @@
   public byte[] orig() {
     // fetch the orig MethodData data between header and dataSize
     Address base = getAddress().addOffsetTo(origField.getOffset());
-    byte[] result = new byte[MethodData.sizeofMethodDataOopDesc];
-    for (int i = 0; i < MethodData.sizeofMethodDataOopDesc; i++) {
+    byte[] result = new byte[(int)origField.getType().getSize()];
+    for (int i = 0; i < result.length; i++) {
       result[i] = base.getJByteAt(i);
     }
     return result;
@@ -116,7 +117,7 @@
   public  long[] data() {
     // Read the data as an array of intptr_t elements
     Address base = dataField.getValue(getAddress());
-    int elements = dataSize() / MethodData.cellSize;
+    int elements = (dataSize() + extraDataSize()) / MethodData.cellSize;
     long[] result = new long[elements];
     for (int i = 0; i < elements; i++) {
       Address value = base.getAddressAt(i * MethodData.cellSize);
@@ -148,8 +149,7 @@
   }
 
   ParametersTypeData<ciKlass,ciMethod> parametersTypeData() {
-    Address base = getAddress().addOffsetTo(origField.getOffset());
-    int di = (int)parametersTypeDataDi.getValue(base);
+    int di = (int)parametersTypeDataDi.getValue(getMetadata().getAddress());
     if (di == -1 || di == -2) {
       return null;
     }
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/DataLayout.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/DataLayout.java
index d55fdbc..3c3630c 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/DataLayout.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/DataLayout.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2021, 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
@@ -81,9 +81,8 @@
     return data.getJShortAt(offset + at) & 0xffff;
   }
 
-  int cellAt(int index) {
-    // Cells are intptr_t sized but only contain ints as raw values
-    return (int)data.getCIntegerAt(offset + cellOffset(index), MethodData.cellSize, false);
+  long cellAt(int index) {
+    return data.getCIntegerAt(offset + cellOffset(index), MethodData.cellSize, false);
   }
 
   public Address addressAt(int index) {
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/MethodData.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/MethodData.java
index ea92fa5..68d7808 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/MethodData.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/MethodData.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2021, 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
@@ -234,8 +234,8 @@
   public void iterateFields(MetadataVisitor visitor) {
     super.iterateFields(visitor);
     visitor.doMetadata(method, true);
-      visitor.doCInt(size, true);
-    }
+    visitor.doCInt(size, true);
+  }
 
   int dataSize() {
     if (dataSize == null) {
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ProfileData.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ProfileData.java
index dce1b83..29a127b 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ProfileData.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ProfileData.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2021, 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
@@ -51,7 +51,7 @@
   }
 
   // Low-level accessors for underlying data
-  int intptrAt(int index) {
+  long intptrAt(int index) {
     //assert(0 <= index && index < cellCount(), "oob");
     return data().cellAt(index);
   }
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/TypeEntries.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/TypeEntries.java
index 8b791b5..16ba553 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/TypeEntries.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/TypeEntries.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2021, 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
@@ -48,17 +48,17 @@
   final MethodDataInterface<K,M> methodData;
 
   boolean wasNullSeen(int index) {
-    int v = pd.intptrAt(index);
+    long v = pd.intptrAt(index);
     return (v & nullSeen) != 0;
   }
 
   boolean isTypeUnknown(int index) {
-    int v = pd.intptrAt(index);
+    long v = pd.intptrAt(index);
     return (v & typeUnknown) != 0;
   }
 
   boolean isTypeNone(int index) {
-    int v = pd.intptrAt(index);
+    long v = pd.intptrAt(index);
     return (v & typeMask) == 0;
   }
 
diff --git a/test/hotspot/jtreg/compiler/ciReplay/CiReplayBase.java b/test/hotspot/jtreg/compiler/ciReplay/CiReplayBase.java
index 7d39496..68313ca 100644
--- a/test/hotspot/jtreg/compiler/ciReplay/CiReplayBase.java
+++ b/test/hotspot/jtreg/compiler/ciReplay/CiReplayBase.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2021, 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
@@ -43,6 +43,7 @@
 import jdk.test.lib.process.OutputAnalyzer;
 import jdk.test.lib.Asserts;
 import jdk.test.lib.Utils;
+import jdk.test.lib.util.CoreUtils;
 
 public abstract class CiReplayBase {
     public static final String REPLAY_FILE_NAME = "test_replay.txt";
@@ -65,17 +66,27 @@
         "-XX:MetaspaceSize=4m", "-XX:MaxMetaspaceSize=16m", "-XX:InitialCodeCacheSize=512k",
         "-XX:ReservedCodeCacheSize=4m", "-XX:ThreadStackSize=512", "-XX:VMThreadStackSize=512",
         "-XX:CompilerThreadStackSize=512", "-XX:ParallelGCThreads=1", "-XX:CICompilerCount=2",
-        "-Xcomp", "-XX:CICrashAt=1", "-XX:+DumpReplayDataOnError",
-        "-XX:+PreferInterpreterNativeStubs", "-XX:+PrintCompilation", REPLAY_FILE_OPTION};
+        "-XX:-BackgroundCompilation", "-XX:CompileCommand=inline,java.io.PrintStream::*",
+        "-XX:+IgnoreUnrecognizedVMOptions", "-XX:TypeProfileLevel=222", // extra profile data as a stress test
+        "-XX:CICrashAt=1", "-XX:+DumpReplayDataOnError",
+        "-XX:+PreferInterpreterNativeStubs", REPLAY_FILE_OPTION};
     private static final String[] REPLAY_OPTIONS = new String[]{DISABLE_COREDUMP_ON_CRASH,
+        "-XX:+IgnoreUnrecognizedVMOptions", "-XX:TypeProfileLevel=222",
         "-XX:+ReplayCompiles", REPLAY_FILE_OPTION};
     protected final Optional<Boolean> runServer;
     private static int dummy;
 
     public static class TestMain {
         public static void main(String[] args) {
-            // Do something because empty methods might not be called/compiled.
-            dummy = 42;
+            for (int i = 0; i < 20_000; i++) {
+                test(i);
+            }
+        }
+
+        static void test(int i) {
+            if ((i % 1000) == 0) {
+                System.out.println("Hello World!");
+            }
         }
     }
 
@@ -103,7 +114,7 @@
 
     public void runTest(boolean needCoreDump, String... args) {
         cleanup();
-        if (generateReplay(needCoreDump)) {
+        if (generateReplay(needCoreDump, args)) {
             testAction();
             cleanup();
         } else {
@@ -143,11 +154,16 @@
             options.addAll(Arrays.asList(REPLAY_GENERATION_OPTIONS));
             options.addAll(Arrays.asList(vmopts));
             options.add(needCoreDump ? ENABLE_COREDUMP_ON_CRASH : DISABLE_COREDUMP_ON_CRASH);
-            options.add(TestMain.class.getName());
             if (needCoreDump) {
-                crashOut = ProcessTools.executeProcess(getTestJvmCommandlineWithPrefix(
-                        RUN_SHELL_NO_LIMIT, options.toArray(new String[0])));
+                // CiReplayBase$TestMain needs to be quoted because of shell eval
+                options.add("-XX:CompileOnly='" + TestMain.class.getName() + "::test'");
+                options.add("'" + TestMain.class.getName() + "'");
+                crashOut = ProcessTools.executeProcess(
+                        CoreUtils.addCoreUlimitCommand(
+                                ProcessTools.createTestJvm(options.toArray(new String[0]))));
             } else {
+                options.add("-XX:CompileOnly=" + TestMain.class.getName() + "::test");
+                options.add(TestMain.class.getName());
                 crashOut = ProcessTools.executeProcess(ProcessTools.createTestJvm(options));
             }
             crashOutputString = crashOut.getOutput();
@@ -159,18 +175,8 @@
             throw new Error("Can't create replay: " + t, t);
         }
         if (needCoreDump) {
-            String coreFileLocation = getCoreFileLocation(crashOutputString);
-            if (coreFileLocation == null) {
-                if (Platform.isOSX()) {
-                    File coresDir = new File("/cores");
-                    if (!coresDir.isDirectory() || !coresDir.canWrite()) {
-                        return false;
-                    }
-                }
-                throw new Error("Couldn't find core file location in: '" + crashOutputString + "'");
-            }
             try {
-                Asserts.assertGT(new File(coreFileLocation).length(), 0L, "Unexpected core size");
+                String coreFileLocation = CoreUtils.getCoreFileLocation(crashOutputString, crashOut.pid());
                 Files.move(Paths.get(coreFileLocation), Paths.get(TEST_CORE_FILE_NAME));
             } catch (IOException ioe) {
                 throw new Error("Can't move core file: " + ioe, ioe);
@@ -250,48 +256,6 @@
         }
     }
 
-    // lets search few possible locations using process output and return existing location
-    private String getCoreFileLocation(String crashOutputString) {
-        Asserts.assertTrue(crashOutputString.contains(LOCATIONS_STRING),
-                "Output doesn't contain the location of core file, see crash.out");
-        String stringWithLocation = Arrays.stream(crashOutputString.split("\\r?\\n"))
-                .filter(str -> str.contains(LOCATIONS_STRING))
-                .findFirst()
-                .get();
-        stringWithLocation = stringWithLocation.substring(stringWithLocation
-                .indexOf(LOCATIONS_STRING) + LOCATIONS_STRING.length());
-        String coreWithPid;
-        if (stringWithLocation.contains("or ") && !Platform.isWindows()) {
-            Matcher m = Pattern.compile("or.* ([^ ]+[^\\)])\\)?").matcher(stringWithLocation);
-            if (!m.find()) {
-                throw new Error("Couldn't find path to core inside location string");
-            }
-            coreWithPid = m.group(1);
-        } else {
-            coreWithPid = stringWithLocation.trim();
-        }
-        if (new File(coreWithPid).exists()) {
-            return coreWithPid;
-        }
-        String justCore = Paths.get("core").toString();
-        if (new File(justCore).exists()) {
-            return justCore;
-        }
-        Path coreWithPidPath = Paths.get(coreWithPid);
-        String justFile = coreWithPidPath.getFileName().toString();
-        if (new File(justFile).exists()) {
-            return justFile;
-        }
-        Path parent = coreWithPidPath.getParent();
-        if (parent != null) {
-            String coreWithoutPid = parent.resolve("core").toString();
-            if (new File(coreWithoutPid).exists()) {
-                return coreWithoutPid;
-            }
-        }
-        return null;
-    }
-
     private String[] getTestJvmCommandlineWithPrefix(String prefix, String... args) {
         try {
             String cmd = ProcessTools.getCommandLine(ProcessTools.createTestJvm(args));
diff --git a/test/hotspot/jtreg/compiler/ciReplay/SABase.java b/test/hotspot/jtreg/compiler/ciReplay/SABase.java
index 405b9f1..db576d7 100644
--- a/test/hotspot/jtreg/compiler/ciReplay/SABase.java
+++ b/test/hotspot/jtreg/compiler/ciReplay/SABase.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2021, 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
@@ -25,6 +25,8 @@
 
 import java.nio.file.Files;
 import java.nio.file.Paths;
+import java.io.BufferedReader;
+import java.io.FileReader;
 import java.io.IOException;
 import java.io.File;
 import java.io.FileInputStream;
@@ -41,7 +43,19 @@
 
     public static void main(String args[]) throws Exception {
         checkSetLimits();
-        new SABase(args).runTest(/* needCoreDump = */ true, args);
+        SABase base = new SABase(args);
+        boolean c2 = base.runServer.orElseThrow(() -> new Error("runServer must be set"));
+        String[] extra = {};
+        if (Platform.isTieredSupported()) {
+            if (c2) {
+                // Replay produced on first compilation. We want that
+                // compilation delayed so profile data is produced.
+                extra = new String[] {"-XX:-TieredCompilation"};
+            } else {
+                extra = new String[] {"-XX:TieredStopAtLevel=1"};
+            }
+        }
+        base.runTest(/* needCoreDump = */ true, extra);
     }
 
     public SABase(String[] args) {
@@ -96,19 +110,42 @@
         File replay = new File(REPLAY_FILE_NAME);
         Asserts.assertTrue(replay.exists() && replay.isFile() && replay.length() > 0,
                 "Replay data wasn't generated by SA");
+        // other than comment lines, content of 2 files should be identical
         try {
-            FileInputStream rep = new FileInputStream(replay);
-            FileInputStream repCopy = new FileInputStream(REPLAY_FILE_COPY);
-            byte repBuffer[] = new byte[512];
-            byte repCopyBuffer[] = new byte[512];
-            boolean filesNotEqual = false;
-            while(rep.available() > 0 && !filesNotEqual) {
-                int count = rep.read(repBuffer);
-                int count2 = repCopy.read(repCopyBuffer);
-                filesNotEqual = count != count2 || Arrays.equals(repBuffer, repCopyBuffer);
+            BufferedReader rep = new BufferedReader(new FileReader(replay));
+            BufferedReader repCopy = new BufferedReader(new FileReader(REPLAY_FILE_COPY));
+            boolean failure = false;
+            while (true) {
+                String l1;
+                while ((l1 = rep.readLine()) != null) {
+                    if (!l1.startsWith("#")) {
+                        break;
+                    }
+                }
+                String l2;
+                while ((l2 = repCopy.readLine()) != null) {
+                    if (!l2.startsWith("#")) {
+                        break;
+                    }
+                }
+                if (l1 == null || l2 == null) {
+                    if (l1 != null || l2 != null) {
+                        System.out.println("Warning: replay files are not equal");
+                        System.out.println("1: " + l1);
+                        System.out.println("2: " + l2);
+                        failure = true;
+                    }
+                    break;
+                }
+                if (!l1.equals(l2)) {
+                    System.out.println("Warning: replay files are not equal");
+                    System.out.println("1: " + l1);
+                    System.out.println("2: " + l2);
+                    failure = true;
+                }
             }
-            if (filesNotEqual) {
-                System.out.println("Warning: replay files are not equal");
+            if (failure) {
+                throw new RuntimeException("Warning: replay files are not equal");
             }
         } catch (IOException ioe) {
             throw new Error("Can't read replay files: " + ioe, ioe);
diff --git a/test/hotspot/jtreg/compiler/ciReplay/VMBase.java b/test/hotspot/jtreg/compiler/ciReplay/VMBase.java
index c8ca9d0..a4271fa 100644
--- a/test/hotspot/jtreg/compiler/ciReplay/VMBase.java
+++ b/test/hotspot/jtreg/compiler/ciReplay/VMBase.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2021, 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,7 +30,7 @@
 public class VMBase extends CiReplayBase {
 
     public static void main(String args[]) {
-        new VMBase(args).runTest(/* needCoreDump = */ false, args);
+        new VMBase(args).runTest(/* needCoreDump = */ false);
     }
 
     public VMBase(String[] args) {
diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbCDSCore.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbCDSCore.java
index 2d00132..f16228c 100644
--- a/test/hotspot/jtreg/serviceability/sa/ClhsdbCDSCore.java
+++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbCDSCore.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2021, 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
@@ -98,7 +98,7 @@
             }
 
             try {
-                coreFileName = CoreUtils.getCoreFileLocation(crashOutput.getStdout());
+                coreFileName = CoreUtils.getCoreFileLocation(crashOutput.getStdout(), crashOutput.pid());
             } catch (Exception e) {
                 cleanup();
                 throw e;
diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbFindPC.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbFindPC.java
index 0a333e7..6b10d80 100644
--- a/test/hotspot/jtreg/serviceability/sa/ClhsdbFindPC.java
+++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbFindPC.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2021, 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
@@ -99,7 +99,7 @@
 
             // Get the core file name if we are debugging a core instead of live process
             if (withCore) {
-                coreFileName = CoreUtils.getCoreFileLocation(theApp.getOutput().getStdout());
+                coreFileName = CoreUtils.getCoreFileLocation(theApp.getOutput().getStdout(), theApp.getPid());
             }
 
             // Run 'jstack -v' command to get the findpc address
diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbPmap.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbPmap.java
index 54e732a..6f0023a 100644
--- a/test/hotspot/jtreg/serviceability/sa/ClhsdbPmap.java
+++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbPmap.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2021, 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
@@ -65,7 +65,7 @@
 
             if (withCore) {
                 String crashOutput = theApp.getOutput().getStdout();
-                coreFileName = CoreUtils.getCoreFileLocation(crashOutput);
+                coreFileName = CoreUtils.getCoreFileLocation(crashOutput, theApp.getPid());
             }
 
             List<String> cmds = List.of("pmap");
diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbPstack.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbPstack.java
index 5eb162f..e4101a8 100644
--- a/test/hotspot/jtreg/serviceability/sa/ClhsdbPstack.java
+++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbPstack.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2021, 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
@@ -65,7 +65,7 @@
 
             if (withCore) {
                 String crashOutput = theApp.getOutput().getStdout();
-                coreFileName = CoreUtils.getCoreFileLocation(crashOutput);
+                coreFileName = CoreUtils.getCoreFileLocation(crashOutput, theApp.getPid());
             }
 
             List<String> cmds = List.of("pstack -v");
diff --git a/test/hotspot/jtreg/serviceability/sa/TestJmapCore.java b/test/hotspot/jtreg/serviceability/sa/TestJmapCore.java
index 662d55a..1c861f8 100644
--- a/test/hotspot/jtreg/serviceability/sa/TestJmapCore.java
+++ b/test/hotspot/jtreg/serviceability/sa/TestJmapCore.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2021, 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
@@ -77,9 +77,9 @@
 
         // If we are going to force a core dump, apply "ulimit -c unlimited" if we can.
         pb = CoreUtils.addCoreUlimitCommand(pb);
-        OutputAnalyzer output =  ProcessTools.executeProcess(pb);
+        OutputAnalyzer output = ProcessTools.executeProcess(pb);
 
-        String coreFileName = CoreUtils.getCoreFileLocation(output.getStdout());
+        String coreFileName = CoreUtils.getCoreFileLocation(output.getStdout(), output.pid());
         File core = new File(coreFileName);
         File dumpFile = new File("heap.hprof");
         JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jhsdb");
diff --git a/test/lib/jdk/test/lib/process/OutputAnalyzer.java b/test/lib/jdk/test/lib/process/OutputAnalyzer.java
index 9860eb8..59a3053 100644
--- a/test/lib/jdk/test/lib/process/OutputAnalyzer.java
+++ b/test/lib/jdk/test/lib/process/OutputAnalyzer.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2021, 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
@@ -567,6 +567,15 @@
     }
 
     /**
+     * Get the process' pid
+     *
+     * @return pid
+     */
+    public long pid() {
+        return buffer.pid();
+    }
+
+    /**
      * Get the contents of the output buffer (stdout and stderr) as list of strings.
      * Output will be split by newlines.
      *
diff --git a/test/lib/jdk/test/lib/process/OutputBuffer.java b/test/lib/jdk/test/lib/process/OutputBuffer.java
index 7adee65..3741ccb 100644
--- a/test/lib/jdk/test/lib/process/OutputBuffer.java
+++ b/test/lib/jdk/test/lib/process/OutputBuffer.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2021, 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
@@ -69,6 +69,13 @@
   public String getStderr();
   public int getExitValue();
 
+  /**
+   * Returns the pid if available
+   *
+   * @return pid
+   */
+  public long pid();
+
   public static OutputBuffer of(Process p, Charset cs) {
     return new LazyOutputBuffer(p, cs);
   }
@@ -157,6 +164,11 @@
         throw new OutputBufferException(e);
       }
     }
+
+    @Override
+    public long pid() {
+      return p.pid();
+    }
   }
 
   class EagerOutputBuffer implements OutputBuffer {
@@ -184,5 +196,10 @@
     public int getExitValue() {
       return exitValue;
     }
+
+    @Override
+    public long pid() {
+      throw new RuntimeException("no process");
+    }
   }
 }
diff --git a/test/lib/jdk/test/lib/util/CoreUtils.java b/test/lib/jdk/test/lib/util/CoreUtils.java
index cfff57b..d7e68e8 100644
--- a/test/lib/jdk/test/lib/util/CoreUtils.java
+++ b/test/lib/jdk/test/lib/util/CoreUtils.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2021, 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
@@ -101,7 +101,7 @@
      * @param crashOutputString {@code String} to search in for the core file path
      * @return Location of core file if found in the output, otherwise {@code null}.
      */
-    public static String getCoreFileLocation(String crashOutputString) throws IOException {
+    public static String getCoreFileLocation(String crashOutputString, long pid) throws IOException {
         unzipCores(new File("."));
 
         // Find the core file
@@ -124,7 +124,8 @@
             return coreFileLocation; // success!
         }
 
-        // See if we can figure out the likely reason the core file was not found.
+        // See if we can figure out the likely reason the core file was not found. Recover from
+        // failure if possible.
         // Throw SkippedException if appropriate.
         if (Platform.isOSX()) {
             File coresDir = new File("/cores");
@@ -152,6 +153,30 @@
                     line = line.trim();
                     System.out.println(line);
                     if (line.startsWith("|")) {
+                        if (line.split("\s", 2)[0].endsWith("systemd-coredump")) {
+                            // A systemd linux system. Try to retrieve core
+                            // file. It can take a few seconds for the system to
+                            // process the just produced core file so we may need to
+                            // retry a few times.
+                            System.out.println("Running systemd-coredump: trying coredumpctl command");
+                            String core = "core";
+                            try {
+                                for (int i = 0; i < 10; i++) {
+                                    Thread.sleep(5000);
+                                    OutputAnalyzer out = ProcessTools.executeProcess("coredumpctl", "dump",  "-1",  "-o", core, String.valueOf(pid));
+                                    if (!out.getOutput().contains("output may be incomplete")) {
+                                        break;
+                                    }
+                                }
+                            } catch(Throwable t) {
+                            }
+                            final File coreFile = new File(core);
+                            if (coreFile.exists()) {
+                                Asserts.assertGT(coreFile.length(), 0L, "Unexpected core size");
+                                System.out.println("coredumpctl succeeded");
+                                return core;
+                            }
+                        }
                         System.out.println(
                             "\nThis system uses a crash report tool ($cat /proc/sys/kernel/core_pattern).\n" +
                             "Core files might not be generated. Please reset /proc/sys/kernel/core_pattern\n" +