1 /*
   2  * Copyright (c) 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 package org.graalvm.compiler.hotspot;
  24 
  25 import java.util.Formatter;
  26 
  27 /**
  28  * Mechanism for checking that the current Java runtime environment supports the minimum JVMCI API
  29  * required by Graal. The {@code JVMCI_VERSION_CHECK} environment variable can be used to ignore a
  30  * failed check ({@code JVMCI_VERSION_CHECK=ignore}) or print a warning (
  31  * {@code JVMCI_VERSION_CHECK=warn}) and continue. Otherwise, a failed check results in an
  32  * {@link InternalError} being raised or, if called from {@link #main(String[])}, the VM exiting
  33  * with a result code of {@code -1}
  34  *
  35  * This class only depends on the JDK so that it can be used without building Graal.
  36  */
  37 class JVMCIVersionCheck {
  38 
  39     private static final int JVMCI8_MIN_MAJOR_VERSION = 0;
  40     private static final int JVMCI8_MIN_MINOR_VERSION = 23;
  41 
  42     // Will be updated once an ea build with the required JVMCI API is available.
  43     private static final int JVMCI9_MIN_EA_BUILD = 143;
  44 
  45     private static void failVersionCheck(boolean exit, String reason, Object... args) {
  46         Formatter errorMessage = new Formatter().format(reason, args);
  47         String javaHome = System.getProperty("java.home");
  48         String vmName = System.getProperty("java.vm.name");
  49         errorMessage.format("Set the JVMCI_VERSION_CHECK environment variable to \"ignore\" to suppress ");
  50         errorMessage.format("this error or to \"warn\" to emit a warning and continue execution.%n");
  51         errorMessage.format("Currently used Java home directory is %s.%n", javaHome);
  52         errorMessage.format("Currently used VM configuration is: %s%n", vmName);
  53         if (System.getProperty("java.specification.version").compareTo("1.9") < 0) {
  54             errorMessage.format("Download the latest JVMCI JDK 8 from http://www.oracle.com/technetwork/oracle-labs/program-languages/downloads/index.html");
  55         } else {
  56             errorMessage.format("Download the latest JDK 9 EA from https://jdk9.java.net/download/");
  57         }
  58         String value = System.getenv("JVMCI_VERSION_CHECK");
  59         if ("warn".equals(value)) {
  60             System.err.println(errorMessage.toString());
  61         } else if ("ignore".equals(value)) {
  62             return;
  63         } else if (exit) {
  64             System.err.println(errorMessage.toString());
  65             System.exit(-1);
  66         } else {
  67             throw new InternalError(errorMessage.toString());
  68         }
  69     }
  70 
  71     static void check(boolean exitOnFailure) {
  72         // Don't use regular expressions to minimize Graal startup time
  73         String vmVersion = System.getProperty("java.vm.version");
  74         if (System.getProperty("java.specification.version").compareTo("1.9") < 0) {
  75             int start = vmVersion.indexOf("-jvmci-");
  76             if (start >= 0) {
  77                 start += "-jvmci-".length();
  78                 int end = vmVersion.indexOf('.', start);
  79                 if (end > 0) {
  80                     int major = Integer.parseInt(vmVersion.substring(start, end));
  81                     start = end + 1;
  82                     end = start;
  83                     while (end < vmVersion.length() && Character.isDigit(vmVersion.charAt(end))) {
  84                         end++;
  85                     }
  86                     int minor = Integer.parseInt(vmVersion.substring(start, end));
  87                     if (major >= JVMCI8_MIN_MAJOR_VERSION && minor >= JVMCI8_MIN_MINOR_VERSION) {
  88                         return;
  89                     }
  90                     failVersionCheck(exitOnFailure, "The VM does not support the minimum JVMCI API version required by Graal: %d.%d < %d.%d.%n",
  91                                     major, minor, JVMCI8_MIN_MAJOR_VERSION, JVMCI8_MIN_MINOR_VERSION);
  92                     return;
  93                 }
  94             }
  95             failVersionCheck(exitOnFailure, "The VM does not support the minimum JVMCI API version required by Graal.%n" +
  96                             "Cannot read JVMCI version from java.vm.version property: %s.%n", vmVersion);
  97         } else {
  98             if (vmVersion.contains("SNAPSHOT")) {
  99                 // The snapshot of http://hg.openjdk.java.net/jdk9/hs tip is expected to work
 100                 return;
 101             }
 102             if (vmVersion.contains("internal")) {
 103                 // Allow local builds
 104                 return;
 105             }
 106             // http://openjdk.java.net/jeps/223
 107             // Only support EA builds until GA is available
 108             if (vmVersion.startsWith("9-ea+")) {
 109                 int start = "9-ea+".length();
 110                 int end = start;
 111                 end = start;
 112                 while (end < vmVersion.length() && Character.isDigit(vmVersion.charAt(end))) {
 113                     end++;
 114                 }
 115                 int build = Integer.parseInt(vmVersion.substring(start, end));
 116                 if (build >= JVMCI9_MIN_EA_BUILD) {
 117                     return;
 118                 }
 119                 failVersionCheck(exitOnFailure, "The VM is an insufficiently recent EA JDK9 build for Graal: %d < %d.%n", build, JVMCI9_MIN_EA_BUILD);
 120                 return;
 121             }
 122             failVersionCheck(exitOnFailure, "The VM does not support the minimum JVMCI API version required by Graal.%n" +
 123                             "Cannot read JDK9 EA build number from java.vm.version property: %s.%n", vmVersion);
 124         }
 125     }
 126 
 127     /**
 128      * Command line interface for performing the check.
 129      */
 130     public static void main(String[] args) {
 131         check(true);
 132     }
 133 }