1 /*
   2  * Copyright (c) 2012, 2015, 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.replacements;
  24 
  25 import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
  26 import static org.graalvm.compiler.core.common.GraalOptions.SnippetCounters;
  27 import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;
  28 
  29 import java.util.EnumMap;
  30 
  31 import org.graalvm.compiler.api.replacements.Snippet;
  32 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
  33 import org.graalvm.compiler.core.common.type.StampFactory;
  34 import org.graalvm.compiler.debug.Debug;
  35 import org.graalvm.compiler.nodes.ConstantNode;
  36 import org.graalvm.compiler.nodes.PiNode;
  37 import org.graalvm.compiler.nodes.ValueNode;
  38 import org.graalvm.compiler.nodes.calc.FloatingNode;
  39 import org.graalvm.compiler.nodes.extended.BoxNode;
  40 import org.graalvm.compiler.nodes.extended.UnboxNode;
  41 import org.graalvm.compiler.nodes.spi.LoweringTool;
  42 import org.graalvm.compiler.phases.util.Providers;
  43 import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
  44 import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
  45 import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
  46 
  47 import jdk.vm.ci.code.TargetDescription;
  48 import jdk.vm.ci.meta.ConstantReflectionProvider;
  49 import jdk.vm.ci.meta.JavaConstant;
  50 import jdk.vm.ci.meta.JavaKind;
  51 import jdk.vm.ci.meta.MetaAccessProvider;
  52 
  53 public class BoxingSnippets implements Snippets {
  54 
  55     @Snippet
  56     public static Object booleanValueOf(boolean value) {
  57         valueOfCounter.inc();
  58         return PiNode.piCast(Boolean.valueOf(value), StampFactory.forNodeIntrinsic());
  59     }
  60 
  61     @Snippet
  62     public static Object byteValueOf(byte value) {
  63         valueOfCounter.inc();
  64         return PiNode.piCast(Byte.valueOf(value), StampFactory.forNodeIntrinsic());
  65     }
  66 
  67     @Snippet
  68     public static Object charValueOf(char value) {
  69         valueOfCounter.inc();
  70         return PiNode.piCast(Character.valueOf(value), StampFactory.forNodeIntrinsic());
  71     }
  72 
  73     @Snippet
  74     public static Object doubleValueOf(double value) {
  75         valueOfCounter.inc();
  76         return PiNode.piCast(Double.valueOf(value), StampFactory.forNodeIntrinsic());
  77     }
  78 
  79     @Snippet
  80     public static Object floatValueOf(float value) {
  81         valueOfCounter.inc();
  82         return PiNode.piCast(Float.valueOf(value), StampFactory.forNodeIntrinsic());
  83     }
  84 
  85     @Snippet
  86     public static Object intValueOf(int value) {
  87         valueOfCounter.inc();
  88         return PiNode.piCast(Integer.valueOf(value), StampFactory.forNodeIntrinsic());
  89     }
  90 
  91     @Snippet
  92     public static Object longValueOf(long value) {
  93         valueOfCounter.inc();
  94         return PiNode.piCast(Long.valueOf(value), StampFactory.forNodeIntrinsic());
  95     }
  96 
  97     @Snippet
  98     public static Object shortValueOf(short value) {
  99         valueOfCounter.inc();
 100         return PiNode.piCast(Short.valueOf(value), StampFactory.forNodeIntrinsic());
 101     }
 102 
 103     @Snippet
 104     public static boolean booleanValue(Boolean value) {
 105         valueOfCounter.inc();
 106         return value.booleanValue();
 107     }
 108 
 109     @Snippet
 110     public static byte byteValue(Byte value) {
 111         valueOfCounter.inc();
 112         return value.byteValue();
 113     }
 114 
 115     @Snippet
 116     public static char charValue(Character value) {
 117         valueOfCounter.inc();
 118         return value.charValue();
 119     }
 120 
 121     @Snippet
 122     public static double doubleValue(Double value) {
 123         valueOfCounter.inc();
 124         return value.doubleValue();
 125     }
 126 
 127     @Snippet
 128     public static float floatValue(Float value) {
 129         valueOfCounter.inc();
 130         return value.floatValue();
 131     }
 132 
 133     @Snippet
 134     public static int intValue(Integer value) {
 135         valueOfCounter.inc();
 136         return value.intValue();
 137     }
 138 
 139     @Snippet
 140     public static long longValue(Long value) {
 141         valueOfCounter.inc();
 142         return value.longValue();
 143     }
 144 
 145     @Snippet
 146     public static short shortValue(Short value) {
 147         valueOfCounter.inc();
 148         return value.shortValue();
 149     }
 150 
 151     public static FloatingNode canonicalizeBoxing(BoxNode box, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) {
 152         ValueNode value = box.getValue();
 153         if (value.isConstant()) {
 154             JavaConstant sourceConstant = value.asJavaConstant();
 155             if (sourceConstant.getJavaKind() != box.getBoxingKind() && sourceConstant.getJavaKind().isNumericInteger()) {
 156                 switch (box.getBoxingKind()) {
 157                     case Boolean:
 158                         sourceConstant = JavaConstant.forBoolean(sourceConstant.asLong() != 0L);
 159                         break;
 160                     case Byte:
 161                         sourceConstant = JavaConstant.forByte((byte) sourceConstant.asLong());
 162                         break;
 163                     case Char:
 164                         sourceConstant = JavaConstant.forChar((char) sourceConstant.asLong());
 165                         break;
 166                     case Short:
 167                         sourceConstant = JavaConstant.forShort((short) sourceConstant.asLong());
 168                         break;
 169                 }
 170             }
 171             JavaConstant boxedConstant = constantReflection.boxPrimitive(sourceConstant);
 172             if (boxedConstant != null && sourceConstant.getJavaKind() == box.getBoxingKind()) {
 173                 return ConstantNode.forConstant(boxedConstant, metaAccess, box.graph());
 174             }
 175         }
 176         return null;
 177     }
 178 
 179     public static class Templates extends AbstractTemplates {
 180 
 181         private final EnumMap<JavaKind, SnippetInfo> boxSnippets = new EnumMap<>(JavaKind.class);
 182         private final EnumMap<JavaKind, SnippetInfo> unboxSnippets = new EnumMap<>(JavaKind.class);
 183 
 184         public Templates(Providers providers, SnippetReflectionProvider snippetReflection, TargetDescription target) {
 185             super(providers, snippetReflection, target);
 186             for (JavaKind kind : new JavaKind[]{JavaKind.Boolean, JavaKind.Byte, JavaKind.Char, JavaKind.Double, JavaKind.Float, JavaKind.Int, JavaKind.Long, JavaKind.Short}) {
 187                 boxSnippets.put(kind, snippet(BoxingSnippets.class, kind.getJavaName() + "ValueOf"));
 188                 unboxSnippets.put(kind, snippet(BoxingSnippets.class, kind.getJavaName() + "Value"));
 189             }
 190         }
 191 
 192         public void lower(BoxNode box, LoweringTool tool) {
 193             FloatingNode canonical = canonicalizeBoxing(box, providers.getMetaAccess(), providers.getConstantReflection());
 194             // if in AOT mode, we don't want to embed boxed constants.
 195             if (canonical != null && !ImmutableCode.getValue()) {
 196                 box.graph().replaceFixedWithFloating(box, canonical);
 197             } else {
 198                 Arguments args = new Arguments(boxSnippets.get(box.getBoxingKind()), box.graph().getGuardsStage(), tool.getLoweringStage());
 199                 args.add("value", box.getValue());
 200 
 201                 SnippetTemplate template = template(args);
 202                 Debug.log("Lowering integerValueOf in %s: node=%s, template=%s, arguments=%s", box.graph(), box, template, args);
 203                 template.instantiate(providers.getMetaAccess(), box, DEFAULT_REPLACER, args);
 204             }
 205         }
 206 
 207         public void lower(UnboxNode unbox, LoweringTool tool) {
 208             Arguments args = new Arguments(unboxSnippets.get(unbox.getBoxingKind()), unbox.graph().getGuardsStage(), tool.getLoweringStage());
 209             args.add("value", unbox.getValue());
 210 
 211             SnippetTemplate template = template(args);
 212             Debug.log("Lowering integerValueOf in %s: node=%s, template=%s, arguments=%s", unbox.graph(), unbox, template, args);
 213             template.instantiate(providers.getMetaAccess(), unbox, DEFAULT_REPLACER, args);
 214         }
 215     }
 216 
 217     private static final SnippetCounter.Group integerCounters = SnippetCounters.getValue() ? new SnippetCounter.Group("Integer intrinsifications") : null;
 218     private static final SnippetCounter valueOfCounter = new SnippetCounter(integerCounters, "valueOf", "valueOf intrinsification");
 219 
 220 }