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 static org.graalvm.compiler.core.common.GraalOptions.HotSpotPrintInlining;
  26 
  27 import java.util.Collection;
  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     public interface Stringify {
  78         String apply(Object o);
  79     }
  80 
  81     public static String join(Collection<?> c, String sep) {
  82         return join(c, sep, "", "", null);
  83     }
  84 
  85     public static String join(Collection<?> c, String sep, String prefix, String suffix, Stringify stringify) {
  86         StringBuilder buf = new StringBuilder(prefix);
  87         boolean first = true;
  88         for (Object e : c) {
  89             if (!first) {
  90                 buf.append(sep);
  91             } else {
  92                 first = false;
  93             }
  94             buf.append(stringify != null ? stringify.apply(e) : String.valueOf(e));
  95         }
  96         buf.append(suffix);
  97         return buf.toString();
  98     }
  99 
 100     /**
 101      * Sets the element at a given position of a list and ensures that this position exists. If the
 102      * list is current shorter than the position, intermediate positions are filled with a given
 103      * value.
 104      *
 105      * @param list the list to put the element into
 106      * @param pos the position at which to insert the element
 107      * @param x the element that should be inserted
 108      * @param filler the filler element that is used for the intermediate positions in case the list
 109      *            is shorter than pos
 110      */
 111     public static <T> void atPutGrow(List<T> list, int pos, T x, T filler) {
 112         if (list.size() < pos + 1) {
 113             while (list.size() < pos + 1) {
 114                 list.add(filler);
 115             }
 116             assert list.size() == pos + 1;
 117         }
 118 
 119         assert list.size() >= pos + 1;
 120         list.set(pos, x);
 121     }
 122 
 123     /**
 124      * Prepends the String {@code indentation} to every line in String {@code lines}, including a
 125      * possibly non-empty line following the final newline.
 126      */
 127     public static String indent(String lines, String indentation) {
 128         if (lines.length() == 0) {
 129             return lines;
 130         }
 131         final String newLine = "\n";
 132         if (lines.endsWith(newLine)) {
 133             return indentation + (lines.substring(0, lines.length() - 1)).replace(newLine, newLine + indentation) + newLine;
 134         }
 135         return indentation + lines.replace(newLine, newLine + indentation);
 136     }
 137 
 138     /**
 139      * Returns the zero value for a given numeric kind.
 140      */
 141     public static JavaConstant zero(JavaKind kind) {
 142         switch (kind) {
 143             case Boolean:
 144                 return JavaConstant.FALSE;
 145             case Byte:
 146                 return JavaConstant.forByte((byte) 0);
 147             case Char:
 148                 return JavaConstant.forChar((char) 0);
 149             case Double:
 150                 return JavaConstant.DOUBLE_0;
 151             case Float:
 152                 return JavaConstant.FLOAT_0;
 153             case Int:
 154                 return JavaConstant.INT_0;
 155             case Long:
 156                 return JavaConstant.LONG_0;
 157             case Short:
 158                 return JavaConstant.forShort((short) 0);
 159             default:
 160                 throw new IllegalArgumentException(kind.toString());
 161         }
 162     }
 163 
 164     /**
 165      * Returns the one value for a given numeric kind.
 166      */
 167     public static JavaConstant one(JavaKind kind) {
 168         switch (kind) {
 169             case Boolean:
 170                 return JavaConstant.TRUE;
 171             case Byte:
 172                 return JavaConstant.forByte((byte) 1);
 173             case Char:
 174                 return JavaConstant.forChar((char) 1);
 175             case Double:
 176                 return JavaConstant.DOUBLE_1;
 177             case Float:
 178                 return JavaConstant.FLOAT_1;
 179             case Int:
 180                 return JavaConstant.INT_1;
 181             case Long:
 182                 return JavaConstant.LONG_1;
 183             case Short:
 184                 return JavaConstant.forShort((short) 1);
 185             default:
 186                 throw new IllegalArgumentException(kind.toString());
 187         }
 188     }
 189 
 190     /**
 191      * Print a HotSpot-style inlining message to the console.
 192      */
 193     public static void printInlining(final ResolvedJavaMethod method, final int bci, final int inliningDepth, final boolean success, final String msg, final Object... args) {
 194         if (HotSpotPrintInlining.getValue()) {
 195             StringBuilder sb = new StringBuilder();
 196             // 1234567
 197             sb.append("        ");     // print timestamp
 198             // 1234
 199             sb.append("     ");        // print compilation number
 200             // % s ! b n
 201             sb.append(String.format("%c%c%c%c%c ", ' ', method.isSynchronized() ? 's' : ' ', ' ', ' ', method.isNative() ? 'n' : ' '));
 202             sb.append("     ");        // more indent
 203             sb.append("    ");         // initial inlining indent
 204             for (int i = 0; i < inliningDepth; i++) {
 205                 sb.append("  ");
 206             }
 207             sb.append(String.format("@ %d  %s   %s%s", bci, methodName(method), success ? "" : "not inlining ", String.format(msg, args)));
 208             TTY.println(sb.toString());
 209         }
 210     }
 211 
 212     private static String methodName(ResolvedJavaMethod method) {
 213         return method.format("%H.%n(%p):%r") + " (" + method.getCodeSize() + " bytes)";
 214     }
 215 }