1 /*
   2  * Copyright (c) 2009, 2011, 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.core.common.util;
  24 
  25 import java.lang.reflect.AccessibleObject;
  26 import java.lang.reflect.Executable;
  27 import java.lang.reflect.Field;
  28 import java.util.List;
  29 
  30 import org.graalvm.compiler.debug.TTY;
  31 
  32 import jdk.vm.ci.meta.JavaConstant;
  33 import jdk.vm.ci.meta.JavaKind;
  34 import jdk.vm.ci.meta.ResolvedJavaMethod;
  35 
  36 /**
  37  * The {@code Util} class contains a motley collection of utility methods used throughout the
  38  * compiler.
  39  */
  40 public class Util {
  41 
  42     private static int getJavaSpecificationVersion() {
  43         String value = System.getProperty("java.specification.version");
  44         if (value.startsWith("1.")) {
  45             value = value.substring(2);
  46         }
  47         return Integer.parseInt(value);
  48     }
  49 
  50     /**
  51      * The integer value corresponding to the value of the {@code java.specification.version} system
  52      * property after any leading {@code "1."} has been stripped.
  53      */
  54     public static final int JAVA_SPECIFICATION_VERSION = getJavaSpecificationVersion();
  55 
  56     /**
  57      * Determines if the Java runtime is version 8 or earlier.
  58      */
  59     public static final boolean Java8OrEarlier = JAVA_SPECIFICATION_VERSION <= 8;
  60 
  61     /**
  62      * Statically cast an object to an arbitrary Object type. Dynamically checked.
  63      */
  64     @SuppressWarnings("unchecked")
  65     public static <T> T uncheckedCast(@SuppressWarnings("unused") Class<T> type, Object object) {
  66         return (T) object;
  67     }
  68 
  69     /**
  70      * Statically cast an object to an arbitrary Object type. Dynamically checked.
  71      */
  72     @SuppressWarnings("unchecked")
  73     public static <T> T uncheckedCast(Object object) {
  74         return (T) object;
  75     }
  76 
  77     /**
  78      * Sets the element at a given position of a list and ensures that this position exists. If the
  79      * list is current shorter than the position, intermediate positions are filled with a given
  80      * value.
  81      *
  82      * @param list the list to put the element into
  83      * @param pos the position at which to insert the element
  84      * @param x the element that should be inserted
  85      * @param filler the filler element that is used for the intermediate positions in case the list
  86      *            is shorter than pos
  87      */
  88     public static <T> void atPutGrow(List<T> list, int pos, T x, T filler) {
  89         if (list.size() < pos + 1) {
  90             while (list.size() < pos + 1) {
  91                 list.add(filler);
  92             }
  93             assert list.size() == pos + 1;
  94         }
  95 
  96         assert list.size() >= pos + 1;
  97         list.set(pos, x);
  98     }
  99 
 100     /**
 101      * Prepends the String {@code indentation} to every line in String {@code lines}, including a
 102      * possibly non-empty line following the final newline.
 103      */
 104     public static String indent(String lines, String indentation) {
 105         if (lines.length() == 0) {
 106             return lines;
 107         }
 108         final String newLine = "\n";
 109         if (lines.endsWith(newLine)) {
 110             return indentation + (lines.substring(0, lines.length() - 1)).replace(newLine, newLine + indentation) + newLine;
 111         }
 112         return indentation + lines.replace(newLine, newLine + indentation);
 113     }
 114 
 115     /**
 116      * Returns the zero value for a given numeric kind.
 117      */
 118     public static JavaConstant zero(JavaKind kind) {
 119         switch (kind) {
 120             case Boolean:
 121                 return JavaConstant.FALSE;
 122             case Byte:
 123                 return JavaConstant.forByte((byte) 0);
 124             case Char:
 125                 return JavaConstant.forChar((char) 0);
 126             case Double:
 127                 return JavaConstant.DOUBLE_0;
 128             case Float:
 129                 return JavaConstant.FLOAT_0;
 130             case Int:
 131                 return JavaConstant.INT_0;
 132             case Long:
 133                 return JavaConstant.LONG_0;
 134             case Short:
 135                 return JavaConstant.forShort((short) 0);
 136             default:
 137                 throw new IllegalArgumentException(kind.toString());
 138         }
 139     }
 140 
 141     /**
 142      * Returns the one value for a given numeric kind.
 143      */
 144     public static JavaConstant one(JavaKind kind) {
 145         switch (kind) {
 146             case Boolean:
 147                 return JavaConstant.TRUE;
 148             case Byte:
 149                 return JavaConstant.forByte((byte) 1);
 150             case Char:
 151                 return JavaConstant.forChar((char) 1);
 152             case Double:
 153                 return JavaConstant.DOUBLE_1;
 154             case Float:
 155                 return JavaConstant.FLOAT_1;
 156             case Int:
 157                 return JavaConstant.INT_1;
 158             case Long:
 159                 return JavaConstant.LONG_1;
 160             case Short:
 161                 return JavaConstant.forShort((short) 1);
 162             default:
 163                 throw new IllegalArgumentException(kind.toString());
 164         }
 165     }
 166 
 167     /**
 168      * Print a HotSpot-style inlining message to the console.
 169      */
 170     public static void printInlining(final ResolvedJavaMethod method, final int bci, final int inliningDepth, final boolean success, final String msg, final Object... args) {
 171         StringBuilder sb = new StringBuilder();
 172         // 1234567
 173         sb.append("        ");     // print timestamp
 174         // 1234
 175         sb.append("     ");        // print compilation number
 176         // % s ! b n
 177         sb.append(String.format("%c%c%c%c%c ", ' ', method.isSynchronized() ? 's' : ' ', ' ', ' ', method.isNative() ? 'n' : ' '));
 178         sb.append("     ");        // more indent
 179         sb.append("    ");         // initial inlining indent
 180         for (int i = 0; i < inliningDepth; i++) {
 181             sb.append("  ");
 182         }
 183         sb.append(String.format("@ %d  %s   %s%s", bci, methodName(method), success ? "" : "not inlining ", String.format(msg, args)));
 184         TTY.println(sb.toString());
 185     }
 186 
 187     private static String methodName(ResolvedJavaMethod method) {
 188         return method.format("%H.%n(%p):%r") + " (" + method.getCodeSize() + " bytes)";
 189     }
 190 
 191     /**
 192      * Calls {@link AccessibleObject#setAccessible(boolean)} on {@code field} with the value
 193      * {@code flag}.
 194      */
 195     public static void setAccessible(Field field, boolean flag) {
 196         if (!Java8OrEarlier) {
 197             ModuleAPI.openForReflectionTo(field.getDeclaringClass(), Util.class);
 198         }
 199         field.setAccessible(flag);
 200     }
 201 
 202     /**
 203      * Calls {@link AccessibleObject#setAccessible(boolean)} on {@code executable} with the value
 204      * {@code flag}.
 205      */
 206     public static void setAccessible(Executable executable, boolean flag) {
 207         if (!Java8OrEarlier) {
 208             ModuleAPI.openForReflectionTo(executable.getDeclaringClass(), Util.class);
 209         }
 210         executable.setAccessible(flag);
 211     }
 212 }