1 /*
   2  * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /* @test LimitSharedSizes
  25  * @summary Test handling of limits on shared space size
  26  * @requires (vm.opt.UseCompressedOops == null) | (vm.opt.UseCompressedOops == true)
  27  * @library /test/lib /runtime/CommandLine/OptionsValidation/common
  28  * @modules java.base/jdk.internal.misc
  29  *          java.management
  30  *          jdk.attach/sun.tools.attach
  31  * @run main LimitSharedSizes
  32  */
  33 
  34 import jdk.test.lib.process.ProcessTools;
  35 import jdk.test.lib.process.OutputAnalyzer;
  36 import jdk.test.lib.Platform;
  37 import optionsvalidation.JVMOptionsUtils;
  38 
  39 public class LimitSharedSizes {
  40     static enum Result {
  41         OUT_OF_RANGE,
  42         TOO_SMALL,
  43         VALID,
  44         VALID_ARCHIVE
  45     }
  46 
  47     static enum Region {
  48         RO, RW, MD, MC
  49     }
  50 
  51     private static final boolean fitsRange(String name, String value) throws RuntimeException {
  52         boolean fits = true;
  53         try {
  54             fits = JVMOptionsUtils.fitsRange(name, value);
  55         } catch (Exception e) {
  56             throw new RuntimeException(e.getMessage());
  57         }
  58         return fits;
  59     }
  60 
  61     private static class SharedSizeTestData {
  62         public String optionName;
  63         public String optionValue;
  64         public Result optionResult;
  65 
  66         public SharedSizeTestData(Region region, String value) {
  67             optionName = "-XX:"+getName(region);
  68             optionValue = value;
  69             if (fitsRange(getName(region), value) == false) {
  70                 optionResult = Result.OUT_OF_RANGE;
  71             } else {
  72                 optionResult = Result.TOO_SMALL;
  73             }
  74         }
  75 
  76         public SharedSizeTestData(Region region, String value, Result result) {
  77             optionName = "-XX:"+getName(region);
  78             optionValue = value;
  79             optionResult = result;
  80         }
  81 
  82         private String getName(Region region) {
  83             String name;
  84             switch (region) {
  85                 case RO:
  86                     name = "SharedReadOnlySize";
  87                     break;
  88                 case RW:
  89                     name = "SharedReadWriteSize";
  90                     break;
  91                 case MD:
  92                     name = "SharedMiscDataSize";
  93                     break;
  94                 case MC:
  95                     name = "SharedMiscCodeSize";
  96                     break;
  97                 default:
  98                     name = "Unknown";
  99                     break;
 100             }
 101             return name;
 102         }
 103 
 104         public Result getResult() {
 105             return optionResult;
 106         }
 107     }
 108 
 109     private static final SharedSizeTestData[] testTable = {
 110         // Too small of a region size should not cause a vm crash.
 111         // It should result in an error message either like the following #1:
 112         // The shared miscellaneous code space is not large enough
 113         // to preload requested classes. Use -XX:SharedMiscCodeSize=
 114         // to increase the initial size of shared miscellaneous code space.
 115         // or #2:
 116         // The shared miscellaneous code space is outside the allowed range
 117         new SharedSizeTestData(Region.RO, "4M"),
 118         new SharedSizeTestData(Region.RW, "4M"),
 119         new SharedSizeTestData(Region.MD, "50k"),
 120         new SharedSizeTestData(Region.MC, "20k"),
 121 
 122         // these values are larger than default ones, and should
 123         // be acceptable and not cause failure
 124         new SharedSizeTestData(Region.RO, "20M", Result.VALID),
 125         new SharedSizeTestData(Region.RW, "20M", Result.VALID),
 126         new SharedSizeTestData(Region.MD, "20M", Result.VALID),
 127         new SharedSizeTestData(Region.MC, "20M", Result.VALID),
 128 
 129         // test with sizes which just meet the minimum required sizes
 130         // the following tests also attempt to use the shared archive
 131         new SharedSizeTestData(Region.RO, Platform.is64bit() ? "10M":"9M", Result.VALID_ARCHIVE),
 132         new SharedSizeTestData(Region.RW, Platform.is64bit() ? "12M":"7M", Result.VALID_ARCHIVE),
 133         new SharedSizeTestData(Region.MD, Platform.is64bit() ? "4M":"2M", Result.VALID_ARCHIVE),
 134         new SharedSizeTestData(Region.MC, "120k", Result.VALID_ARCHIVE),
 135     };
 136 
 137     public static void main(String[] args) throws Exception {
 138         int counter = 0;
 139         for (SharedSizeTestData td : testTable) {
 140             String fileName = "LimitSharedSizes" + counter + ".jsa";
 141             counter++;
 142 
 143             String option = td.optionName + "=" + td.optionValue;
 144             System.out.println("testing option number <" + counter + ">");
 145             System.out.println("testing option <" + option + ">");
 146 
 147             ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
 148                "-XX:+UnlockDiagnosticVMOptions",
 149                "-XX:SharedArchiveFile=./" + fileName,
 150                option,
 151                "-Xshare:dump");
 152 
 153             OutputAnalyzer output = new OutputAnalyzer(pb.start());
 154 
 155             switch (td.getResult()) {
 156                 case VALID:
 157                 case VALID_ARCHIVE:
 158                 {
 159                   output.shouldNotContain("space is not large enough");
 160                   output.shouldHaveExitValue(0);
 161 
 162                   if (td.getResult() == Result.VALID_ARCHIVE) {
 163                       // try to use the archive
 164                       pb = ProcessTools.createJavaProcessBuilder(
 165                          "-XX:+UnlockDiagnosticVMOptions",
 166                          "-XX:SharedArchiveFile=./" + fileName,
 167                          "-XX:+PrintSharedArchiveAndExit",
 168                          "-version");
 169 
 170                       try {
 171                           output = new OutputAnalyzer(pb.start());
 172                           output.shouldContain("archive is valid");
 173                       } catch (RuntimeException e) {
 174                           // if sharing failed due to ASLR or similar reasons,
 175                           // check whether sharing was attempted at all (UseSharedSpaces)
 176                           if ((output.getOutput().contains("Unable to use shared archive") ||
 177                                output.getOutput().contains("Unable to map ReadOnly shared space at required address.") ||
 178                                output.getOutput().contains("Unable to map ReadWrite shared space at required address.") ||
 179                                output.getOutput().contains("Unable to reserve shared space at required address")) &&
 180                                output.getExitValue() == 1) {
 181                                System.out.println("Unable to use shared archive: test not executed; assumed passed");
 182                                continue;
 183                           }
 184                       }
 185                       output.shouldHaveExitValue(0);
 186                   }
 187                 }
 188                 break;
 189                 case TOO_SMALL:
 190                 {
 191                     output.shouldContain("space is not large enough");
 192                     output.shouldHaveExitValue(2);
 193                 }
 194                 break;
 195                 case OUT_OF_RANGE:
 196                 {
 197                     output.shouldContain("outside the allowed range");
 198                     output.shouldHaveExitValue(1);
 199                 }
 200                 break;
 201             }
 202         }
 203     }
 204 }