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 * @library /test/lib /runtime/CommandLine/OptionsValidation/common
27 * @modules java.base/jdk.internal.misc
28 *          java.management
29 *          jdk.attach/sun.tools.attach
30 * @run main LimitSharedSizes
31 */
32
33import jdk.test.lib.process.ProcessTools;
34import jdk.test.lib.process.OutputAnalyzer;
35import jdk.test.lib.Platform;
36import optionsvalidation.JVMOptionsUtils;
37
38public class LimitSharedSizes {
39    static enum Result {
40        OUT_OF_RANGE,
41        TOO_SMALL,
42        VALID,
43        VALID_ARCHIVE
44    }
45
46    static enum Region {
47        RO, RW, MD, MC
48    }
49
50    private static final boolean fitsRange(String name, String value) throws RuntimeException {
51        boolean fits = true;
52        try {
53            fits = JVMOptionsUtils.fitsRange(name, value);
54        } catch (Exception e) {
55            throw new RuntimeException(e.getMessage());
56        }
57        return fits;
58    }
59
60    private static class SharedSizeTestData {
61        public String optionName;
62        public String optionValue;
63        public Result optionResult;
64
65        public SharedSizeTestData(Region region, String value) {
66            optionName = "-XX:"+getName(region);
67            optionValue = value;
68            if (fitsRange(getName(region), value) == false) {
69                optionResult = Result.OUT_OF_RANGE;
70            } else {
71                optionResult = Result.TOO_SMALL;
72            }
73        }
74
75        public SharedSizeTestData(Region region, String value, Result result) {
76            optionName = "-XX:"+getName(region);
77            optionValue = value;
78            optionResult = result;
79        }
80
81        private String getName(Region region) {
82            String name;
83            switch (region) {
84                case RO:
85                    name = "SharedReadOnlySize";
86                    break;
87                case RW:
88                    name = "SharedReadWriteSize";
89                    break;
90                case MD:
91                    name = "SharedMiscDataSize";
92                    break;
93                case MC:
94                    name = "SharedMiscCodeSize";
95                    break;
96                default:
97                    name = "Unknown";
98                    break;
99            }
100            return name;
101        }
102
103        public Result getResult() {
104            return optionResult;
105        }
106    }
107
108    private static final SharedSizeTestData[] testTable = {
109        // Too small of a region size should not cause a vm crash.
110        // It should result in an error message either like the following #1:
111        // The shared miscellaneous code space is not large enough
112        // to preload requested classes. Use -XX:SharedMiscCodeSize=
113        // to increase the initial size of shared miscellaneous code space.
114        // or #2:
115        // The shared miscellaneous code space is outside the allowed range
116        new SharedSizeTestData(Region.RO, "4M"),
117        new SharedSizeTestData(Region.RW, "4M"),
118        new SharedSizeTestData(Region.MD, "50k"),
119        new SharedSizeTestData(Region.MC, "20k"),
120
121        // these values are larger than default ones, and should
122        // be acceptable and not cause failure
123        new SharedSizeTestData(Region.RO, "20M", Result.VALID),
124        new SharedSizeTestData(Region.RW, "20M", Result.VALID),
125        new SharedSizeTestData(Region.MD, "20M", Result.VALID),
126        new SharedSizeTestData(Region.MC, "20M", Result.VALID),
127
128        // test with sizes which just meet the minimum required sizes
129        // the following tests also attempt to use the shared archive
130        new SharedSizeTestData(Region.RO, Platform.is64bit() ? "10M":"9M", Result.VALID_ARCHIVE),
131        new SharedSizeTestData(Region.RW, Platform.is64bit() ? "12M":"7M", Result.VALID_ARCHIVE),
132        new SharedSizeTestData(Region.MD, Platform.is64bit() ? "4M":"2M", Result.VALID_ARCHIVE),
133        new SharedSizeTestData(Region.MC, "120k", Result.VALID_ARCHIVE),
134    };
135
136    public static void main(String[] args) throws Exception {
137        int counter = 0;
138        for (SharedSizeTestData td : testTable) {
139            String fileName = "LimitSharedSizes" + counter + ".jsa";
140            counter++;
141
142            String option = td.optionName + "=" + td.optionValue;
143            System.out.println("testing option number <" + counter + ">");
144            System.out.println("testing option <" + option + ">");
145
146            ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
147               "-XX:+UnlockDiagnosticVMOptions",
148               "-XX:SharedArchiveFile=./" + fileName,
149               option,
150               "-Xshare:dump");
151
152            OutputAnalyzer output = new OutputAnalyzer(pb.start());
153
154            switch (td.getResult()) {
155                case VALID:
156                case VALID_ARCHIVE:
157                {
158                  output.shouldNotContain("space is not large enough");
159                  output.shouldHaveExitValue(0);
160
161                  if (td.getResult() == Result.VALID_ARCHIVE) {
162                      // try to use the archive
163                      pb = ProcessTools.createJavaProcessBuilder(
164                         "-XX:+UnlockDiagnosticVMOptions",
165                         "-XX:SharedArchiveFile=./" + fileName,
166                         "-XX:+PrintSharedArchiveAndExit",
167                         "-version");
168
169                      try {
170                          output = new OutputAnalyzer(pb.start());
171                          output.shouldContain("archive is valid");
172                      } catch (RuntimeException e) {
173                          // if sharing failed due to ASLR or similar reasons,
174                          // check whether sharing was attempted at all (UseSharedSpaces)
175                          if ((output.getOutput().contains("Unable to use shared archive") ||
176                               output.getOutput().contains("Unable to map ReadOnly shared space at required address.") ||
177                               output.getOutput().contains("Unable to map ReadWrite shared space at required address.") ||
178                               output.getOutput().contains("Unable to reserve shared space at required address")) &&
179                               output.getExitValue() == 1) {
180                               System.out.println("Unable to use shared archive: test not executed; assumed passed");
181                               continue;
182                          }
183                      }
184                      output.shouldHaveExitValue(0);
185                  }
186                }
187                break;
188                case TOO_SMALL:
189                {
190                    output.shouldContain("space is not large enough");
191                    output.shouldHaveExitValue(2);
192                }
193                break;
194                case OUT_OF_RANGE:
195                {
196                    output.shouldContain("outside the allowed range");
197                    output.shouldHaveExitValue(1);
198                }
199                break;
200            }
201        }
202    }
203}
204