8209807: improve handling exception in requires.VMProps
authoriignatyev
Fri, 22 Feb 2019 14:39:57 -0800
changeset 53906 a6fb5e60588f
parent 53905 5f8ab857f7e1
child 53907 c1885a1d62a3
8209807: improve handling exception in requires.VMProps Reviewed-by: vlivanov, mseledtsov
test/jtreg-ext/requires/VMProps.java
--- a/test/jtreg-ext/requires/VMProps.java	Fri Feb 22 20:42:01 2019 +0100
+++ b/test/jtreg-ext/requires/VMProps.java	Fri Feb 22 14:39:57 2019 -0800
@@ -37,6 +37,7 @@
 import java.util.Properties;
 import java.util.concurrent.Callable;
 import java.util.concurrent.TimeUnit;
+import java.util.function.Supplier;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -49,13 +50,31 @@
 /**
  * The Class to be invoked by jtreg prior Test Suite execution to
  * collect information about VM.
- * Do not use any API's that may not be available in all target VMs.
+ * Do not use any APIs that may not be available in all target VMs.
  * Properties set by this Class will be available in the @requires expressions.
  */
 public class VMProps implements Callable<Map<String, String>> {
+    // value known to jtreg as an indicator of error state
+    private static final String ERROR_STATE = "__ERROR__";
 
     private static final WhiteBox WB = WhiteBox.getWhiteBox();
 
+    private static class SafeMap {
+        private final Map<String, String> map = new HashMap<>();
+
+        public void put(String key, Supplier<String> s) {
+            String value;
+            try {
+                value = s.get();
+            } catch (Throwable t) {
+                System.err.println("failed to get value for " + key);
+                t.printStackTrace(System.err);
+                value = ERROR_STATE + t;
+            }
+            map.put(key, value);
+        }
+    }
+
     /**
      * Collects information about VM properties.
      * This method will be invoked by jtreg.
@@ -64,58 +83,58 @@
      */
     @Override
     public Map<String, String> call() {
-        Map<String, String> map = new HashMap<>();
-        map.put("vm.flavor", vmFlavor());
-        map.put("vm.compMode", vmCompMode());
-        map.put("vm.bits", vmBits());
-        map.put("vm.flightRecorder", vmFlightRecorder());
-        map.put("vm.simpleArch", vmArch());
-        map.put("vm.debug", vmDebug());
-        map.put("vm.jvmci", vmJvmci());
-        map.put("vm.emulatedClient", vmEmulatedClient());
+        SafeMap map = new SafeMap();
+        map.put("vm.flavor", this::vmFlavor);
+        map.put("vm.compMode", this::vmCompMode);
+        map.put("vm.bits", this::vmBits);
+        map.put("vm.flightRecorder", this::vmFlightRecorder);
+        map.put("vm.simpleArch", this::vmArch);
+        map.put("vm.debug", this::vmDebug);
+        map.put("vm.jvmci", this::vmJvmci);
+        map.put("vm.emulatedClient", this::vmEmulatedClient);
         // vm.hasSA is "true" if the VM contains the serviceability agent
         // and jhsdb.
-        map.put("vm.hasSA", vmHasSA());
+        map.put("vm.hasSA", this::vmHasSA);
         // vm.hasSAandCanAttach is "true" if the VM contains the serviceability agent
         // and jhsdb and it can attach to the VM.
-        map.put("vm.hasSAandCanAttach", vmHasSAandCanAttach());
+        map.put("vm.hasSAandCanAttach", this::vmHasSAandCanAttach);
         // vm.hasJFR is "true" if JFR is included in the build of the VM and
         // so tests can be executed.
-        map.put("vm.hasJFR", vmHasJFR());
-        map.put("vm.cpu.features", cpuFeatures());
-        map.put("vm.rtm.cpu", vmRTMCPU());
-        map.put("vm.rtm.compiler", vmRTMCompiler());
-        map.put("vm.aot", vmAOT());
-        map.put("vm.aot.enabled", vmAotEnabled());
+        map.put("vm.hasJFR", this::vmHasJFR);
+        map.put("vm.cpu.features", this::cpuFeatures);
+        map.put("vm.rtm.cpu", this::vmRTMCPU);
+        map.put("vm.rtm.compiler", this::vmRTMCompiler);
+        map.put("vm.aot", this::vmAOT);
+        map.put("vm.aot.enabled", this::vmAotEnabled);
         // vm.cds is true if the VM is compiled with cds support.
-        map.put("vm.cds", vmCDS());
-        map.put("vm.cds.custom.loaders", vmCDSForCustomLoaders());
-        map.put("vm.cds.archived.java.heap", vmCDSForArchivedJavaHeap());
+        map.put("vm.cds", this::vmCDS);
+        map.put("vm.cds.custom.loaders", this::vmCDSForCustomLoaders);
+        map.put("vm.cds.archived.java.heap", this::vmCDSForArchivedJavaHeap);
         // vm.graal.enabled is true if Graal is used as JIT
-        map.put("vm.graal.enabled", isGraalEnabled());
-        map.put("vm.compiler1.enabled", isCompiler1Enabled());
-        map.put("vm.compiler2.enabled", isCompiler2Enabled());
-        map.put("docker.support", dockerSupport());
-        map.put("release.implementor", implementor());
-        map.put("test.vm.gc.nvdimm", isNvdimmTestEnabled());
+        map.put("vm.graal.enabled", this::isGraalEnabled);
+        map.put("vm.compiler1.enabled", this::isCompiler1Enabled);
+        map.put("vm.compiler2.enabled", this::isCompiler2Enabled);
+        map.put("docker.support", this::dockerSupport);
+        map.put("release.implementor", this::implementor);
+        map.put("test.vm.gc.nvdimm", this::isNvdimmTestEnabled);
         vmGC(map); // vm.gc.X = true/false
         vmOptFinalFlags(map);
 
-        VMProps.dump(map);
-        return map;
+        dump(map.map);
+        return map.map;
     }
 
     /**
-     * Prints a stack trace before returning null.
+     * Print a stack trace before returning error state;
      * Used by the various helper functions which parse information from
      * VM properties in the case where they don't find an expected property
-     * or a propoerty doesn't conform to an expected format.
+     * or a property doesn't conform to an expected format.
      *
-     * @return null
+     * @return {@link #ERROR_STATE}
      */
-    private String nullWithException(String message) {
+    private String errorWithMessage(String message) {
         new Exception(message).printStackTrace();
-        return null;
+        return ERROR_STATE + message;
     }
 
     /**
@@ -125,8 +144,7 @@
         String arch = System.getProperty("os.arch");
         if (arch.equals("x86_64") || arch.equals("amd64")) {
             return "x64";
-        }
-        else if (arch.contains("86")) {
+        } else if (arch.contains("86")) {
             return "x86";
         } else {
             return arch;
@@ -140,7 +158,7 @@
         // E.g. "Java HotSpot(TM) 64-Bit Server VM"
         String vmName = System.getProperty("java.vm.name");
         if (vmName == null) {
-            return nullWithException("Can't get 'java.vm.name' property");
+            return errorWithMessage("Can't get 'java.vm.name' property");
         }
 
         Pattern startP = Pattern.compile(".* (\\S+) VM");
@@ -148,7 +166,7 @@
         if (m.matches()) {
             return m.group(1).toLowerCase();
         }
-        return nullWithException("Can't get VM flavor from 'java.vm.name'");
+        return errorWithMessage("Can't get VM flavor from 'java.vm.name'");
     }
 
     /**
@@ -158,16 +176,17 @@
         // E.g. "mixed mode"
         String vmInfo = System.getProperty("java.vm.info");
         if (vmInfo == null) {
-            return nullWithException("Can't get 'java.vm.info' property");
+            return errorWithMessage("Can't get 'java.vm.info' property");
         }
-        if (vmInfo.toLowerCase().indexOf("mixed mode") != -1) {
+        vmInfo = vmInfo.toLowerCase();
+        if (vmInfo.contains("mixed mode")) {
             return "Xmixed";
-        } else if (vmInfo.toLowerCase().indexOf("compiled mode") != -1) {
+        } else if (vmInfo.contains("compiled mode")) {
             return "Xcomp";
-        } else if (vmInfo.toLowerCase().indexOf("interpreted mode") != -1) {
+        } else if (vmInfo.contains("interpreted mode")) {
             return "Xint";
         } else {
-            return nullWithException("Can't get compilation mode from 'java.vm.info'");
+            return errorWithMessage("Can't get compilation mode from 'java.vm.info'");
         }
     }
 
@@ -179,7 +198,7 @@
         if (dataModel != null) {
             return dataModel;
         } else {
-            return nullWithException("Can't get 'sun.arch.data.model' property");
+            return errorWithMessage("Can't get 'sun.arch.data.model' property");
         }
     }
 
@@ -206,7 +225,7 @@
         if (debug != null) {
             return "" + debug.contains("debug");
         } else {
-            return nullWithException("Can't get 'jdk.debug' property");
+            return errorWithMessage("Can't get 'jdk.debug' property");
         }
     }
 
@@ -224,7 +243,7 @@
     protected String vmEmulatedClient() {
         String vmInfo = System.getProperty("java.vm.info");
         if (vmInfo == null) {
-            return "false";
+            return errorWithMessage("Can't get 'java.vm.info' property");
         }
         return "" + vmInfo.contains(" emulated-client");
     }
@@ -241,30 +260,34 @@
      * Example vm.gc.G1=true means:
      *    VM supports G1
      *    User either set G1 explicitely (-XX:+UseG1GC) or did not set any GC
+     *
      * @param map - property-value pairs
      */
-    protected void vmGC(Map<String, String> map) {
+    protected void vmGC(SafeMap map) {
         for (GC gc: GC.values()) {
-            boolean isAcceptable = gc.isSupported() && (gc.isSelected() || GC.isSelectedErgonomically());
-            map.put("vm.gc." + gc.name(), "" + isAcceptable);
+            map.put("vm.gc." + gc.name(),
+                    () -> "" + (gc.isSupported()
+                            && (gc.isSelected() || GC.isSelectedErgonomically())));
         }
     }
 
     /**
      * Selected final flag.
+     *
      * @param map - property-value pairs
      * @param flagName - flag name
      */
-    private void vmOptFinalFlag(Map<String, String> map, String flagName) {
-        String value = String.valueOf(WB.getBooleanVMFlag(flagName));
-        map.put("vm.opt.final." + flagName, value);
+    private void vmOptFinalFlag(SafeMap map, String flagName) {
+        map.put("vm.opt.final." + flagName,
+                () -> String.valueOf(WB.getBooleanVMFlag(flagName)));
     }
 
     /**
      * Selected sets of final flags.
+     *
      * @param map - property-value pairs
      */
-    protected void vmOptFinalFlags(Map<String, String> map) {
+    protected void vmOptFinalFlags(SafeMap map) {
         vmOptFinalFlag(map, "ClassUnloading");
         vmOptFinalFlag(map, "UseCompressedOops");
         vmOptFinalFlag(map, "EnableJVMCI");
@@ -286,10 +309,8 @@
         try {
             return "" + Platform.shouldSAAttach();
         } catch (IOException e) {
-            System.out.println("Checking whether SA can attach to the VM failed.");
             e.printStackTrace();
-            // Run the tests anyways.
-            return "true";
+            return errorWithMessage("Checking whether SA can attach to the VM failed.:" + e);
         }
     }
 
@@ -350,11 +371,7 @@
      * @return true if CDS is supported by the VM to be tested.
      */
     protected String vmCDS() {
-        if (WB.isCDSIncludedInVmBuild()) {
-            return "true";
-        } else {
-            return "false";
-        }
+        return "" + WB.isCDSIncludedInVmBuild();
     }
 
     /**
@@ -363,11 +380,7 @@
      * @return true if CDS provides support for customer loader in the VM to be tested.
      */
     protected String vmCDSForCustomLoaders() {
-        if (vmCDS().equals("true") && Platform.areCustomLoadersSupportedForCDS()) {
-            return "true";
-        } else {
-            return "false";
-        }
+        return "" + ("true".equals(vmCDS()) && Platform.areCustomLoadersSupportedForCDS());
     }
 
     /**
@@ -376,11 +389,7 @@
      * @return true if CDS provides support for archive Java heap regions in the VM to be tested.
      */
     protected String vmCDSForArchivedJavaHeap() {
-      if (vmCDS().equals("true") && WB.isJavaHeapArchiveSupported()) {
-            return "true";
-        } else {
-            return "false";
-        }
+        return "" + ("true".equals(vmCDS()) && WB.isJavaHeapArchiveSupported());
     }
 
     /**
@@ -389,7 +398,7 @@
      * @return true if Graal is used as JIT compiler.
      */
     protected String isGraalEnabled() {
-        return Compiler.isGraalEnabled() ? "true" : "false";
+        return "" + Compiler.isGraalEnabled();
     }
 
     /**
@@ -398,7 +407,7 @@
      * @return true if Compiler1 is used as JIT compiler, either alone or as part of the tiered system.
      */
     protected String isCompiler1Enabled() {
-        return Compiler.isC1Enabled() ? "true" : "false";
+        return "" + Compiler.isC1Enabled();
     }
 
     /**
@@ -407,7 +416,7 @@
      * @return true if Compiler2 is used as JIT compiler, either alone or as part of the tiered system.
      */
     protected String isCompiler2Enabled() {
-        return Compiler.isC2Enabled() ? "true" : "false";
+        return "" + Compiler.isC2Enabled();
     }
 
    /**
@@ -425,14 +434,11 @@
 
            if (Platform.isX64()) {
               isSupported = true;
-           }
-           else if (Platform.isAArch64()) {
+           } else if (Platform.isAArch64()) {
               isSupported = true;
-           }
-           else if (Platform.isS390x()) {
+           } else if (Platform.isS390x()) {
               isSupported = true;
-           }
-           else if (arch.equals("ppc64le")) {
+           } else if (arch.equals("ppc64le")) {
               isSupported = true;
            }
         }
@@ -445,7 +451,7 @@
            }
          }
 
-        return (isSupported) ? "true" : "false";
+        return "" + isSupported;
     }
 
     private boolean checkDockerSupport() throws IOException, InterruptedException {
@@ -456,30 +462,27 @@
         return (p.exitValue() == 0);
     }
 
-
     private String implementor() {
         try (InputStream in = new BufferedInputStream(new FileInputStream(
                 System.getProperty("java.home") + "/release"))) {
             Properties properties = new Properties();
             properties.load(in);
             String implementorProperty = properties.getProperty("IMPLEMENTOR");
-            return (implementorProperty == null) ? "null" : implementorProperty.replace("\"", "");
+            if (implementorProperty != null) {
+                return implementorProperty.replace("\"", "");
+            }
+            return errorWithMessage("Can't get 'IMPLEMENTOR' property from 'release' file");
         } catch (IOException e) {
             e.printStackTrace();
+            return errorWithMessage("Failed to read 'release' file " + e);
         }
-        return null;
     }
 
     private String isNvdimmTestEnabled() {
-        String isEnbled = System.getenv("TEST_VM_GC_NVDIMM");
-        if (isEnbled != null && isEnbled.toLowerCase().equals("true")) {
-            return "true";
-        }
-        return "false";
+        String isEnabled = System.getenv("TEST_VM_GC_NVDIMM");
+        return "" + "true".equalsIgnoreCase(isEnabled);
     }
 
-
-
     /**
      * Dumps the map to the file if the file name is given as the property.
      * This functionality could be helpful to know context in the real
@@ -495,7 +498,8 @@
         List<String> lines = new ArrayList<>();
         map.forEach((k, v) -> lines.add(k + ":" + v));
         try {
-            Files.write(Paths.get(dumpFileName), lines, StandardOpenOption.APPEND);
+            Files.write(Paths.get(dumpFileName), lines,
+                    StandardOpenOption.APPEND, StandardOpenOption.CREATE);
         } catch (IOException e) {
             throw new RuntimeException("Failed to dump properties into '"
                     + dumpFileName + "'", e);
@@ -504,6 +508,7 @@
 
     /**
      * This method is for the testing purpose only.
+     *
      * @param args
      */
     public static void main(String args[]) {