1 /*
   2  * Copyright (c) 2009, 2018, 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 
  25 package org.graalvm.compiler.nodes;
  26 
  27 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
  28 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
  29 
  30 import java.util.Map;
  31 
  32 import org.graalvm.compiler.core.common.LIRKind;
  33 import org.graalvm.compiler.core.common.type.AbstractObjectStamp;
  34 import org.graalvm.compiler.core.common.type.FloatStamp;
  35 import org.graalvm.compiler.core.common.type.IntegerStamp;
  36 import org.graalvm.compiler.core.common.type.Stamp;
  37 import org.graalvm.compiler.core.common.type.StampFactory;
  38 import org.graalvm.compiler.debug.GraalError;
  39 import org.graalvm.compiler.graph.Node;
  40 import org.graalvm.compiler.graph.NodeClass;
  41 import org.graalvm.compiler.graph.iterators.NodeIterable;
  42 import org.graalvm.compiler.lir.ConstantValue;
  43 import org.graalvm.compiler.nodeinfo.NodeInfo;
  44 import org.graalvm.compiler.nodeinfo.Verbosity;
  45 import org.graalvm.compiler.nodes.calc.FloatingNode;
  46 import org.graalvm.compiler.nodes.spi.ArrayLengthProvider;
  47 import org.graalvm.compiler.nodes.spi.LIRLowerable;
  48 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
  49 
  50 import jdk.vm.ci.code.CodeUtil;
  51 import jdk.vm.ci.meta.Constant;
  52 import jdk.vm.ci.meta.ConstantReflectionProvider;
  53 import jdk.vm.ci.meta.JavaConstant;
  54 import jdk.vm.ci.meta.JavaKind;
  55 import jdk.vm.ci.meta.MetaAccessProvider;
  56 import jdk.vm.ci.meta.PrimitiveConstant;
  57 
  58 /**
  59  * The {@code ConstantNode} represents a {@link Constant constant}.
  60  */
  61 @NodeInfo(nameTemplate = "C({p#rawvalue}) {p#stampKind}", cycles = CYCLES_0, size = SIZE_1)
  62 public final class ConstantNode extends FloatingNode implements LIRLowerable, ArrayLengthProvider {
  63 
  64     public static final NodeClass<ConstantNode> TYPE = NodeClass.create(ConstantNode.class);
  65 
  66     protected final Constant value;
  67 
  68     private final int stableDimension;
  69     private final boolean isDefaultStable;
  70 
  71     private static ConstantNode createPrimitive(JavaConstant value) {
  72         assert value.getJavaKind() != JavaKind.Object;
  73         return new ConstantNode(value, StampFactory.forConstant(value));
  74     }
  75 
  76     /**
  77      * Constructs a new node representing the specified constant.
  78      *
  79      * @param value the constant
  80      */
  81     public ConstantNode(Constant value, Stamp stamp) {
  82         this(value, stamp, 0, false);
  83     }
  84 
  85     private ConstantNode(Constant value, Stamp stamp, int stableDimension, boolean isDefaultStable) {
  86         super(TYPE, stamp);
  87         assert stamp != null && stamp.isCompatible(value) : stamp + " " + value;
  88         this.value = value;
  89         this.stableDimension = stableDimension;
  90         if (stableDimension == 0) {
  91             /*
  92              * Ensure that isDefaultStable has a canonical value to avoid having two constant nodes
  93              * that only differ in this field. The value of isDefaultStable is only used when we
  94              * have a stable array dimension.
  95              */
  96             this.isDefaultStable = false;
  97         } else {
  98             this.isDefaultStable = isDefaultStable;
  99         }
 100     }
 101 
 102     /**
 103      * @return the constant value represented by this node
 104      */
 105     public Constant getValue() {
 106         return value;
 107     }
 108 
 109     /**
 110      * @return the number of stable dimensions if this is a stable array, otherwise 0
 111      */
 112     public int getStableDimension() {
 113         return stableDimension;
 114     }
 115 
 116     /**
 117      * @return true if this is a stable array and the default elements are considered stable
 118      */
 119     public boolean isDefaultStable() {
 120         return isDefaultStable;
 121     }
 122 
 123     /**
 124      * Gathers all the {@link ConstantNode}s that are inputs to the
 125      * {@linkplain StructuredGraph#getNodes() live nodes} in a given graph.
 126      */
 127     public static NodeIterable<ConstantNode> getConstantNodes(StructuredGraph graph) {
 128         return graph.getNodes().filter(ConstantNode.class);
 129     }
 130 
 131     /**
 132      * Replaces this node at its usages with another node.
 133      */
 134     public void replace(StructuredGraph graph, Node replacement) {
 135         assert graph == graph();
 136         replaceAtUsagesAndDelete(replacement);
 137     }
 138 
 139     @Override
 140     public void generate(NodeLIRBuilderTool gen) {
 141         LIRKind kind = gen.getLIRGeneratorTool().getLIRKind(stamp(NodeView.DEFAULT));
 142         if (onlyUsedInVirtualState()) {
 143             gen.setResult(this, new ConstantValue(kind, value));
 144         } else {
 145             gen.setResult(this, gen.getLIRGeneratorTool().emitConstant(kind, value));
 146         }
 147     }
 148 
 149     private boolean onlyUsedInVirtualState() {
 150         for (Node n : this.usages()) {
 151             if (n instanceof VirtualState) {
 152                 // Only virtual usage.
 153             } else {
 154                 return false;
 155             }
 156         }
 157         return true;
 158     }
 159 
 160     public static ConstantNode forConstant(JavaConstant constant, MetaAccessProvider metaAccess, StructuredGraph graph) {
 161         if (constant.getJavaKind().getStackKind() == JavaKind.Int && constant.getJavaKind() != JavaKind.Int) {
 162             return forInt(constant.asInt(), graph);
 163         }
 164         if (constant.getJavaKind() == JavaKind.Object) {
 165             return unique(graph, new ConstantNode(constant, StampFactory.forConstant(constant, metaAccess)));
 166         } else {
 167             return unique(graph, createPrimitive(constant));
 168         }
 169     }
 170 
 171     public static ConstantNode forConstant(JavaConstant constant, int stableDimension, boolean isDefaultStable, MetaAccessProvider metaAccess) {
 172         if (constant.getJavaKind().getStackKind() == JavaKind.Int && constant.getJavaKind() != JavaKind.Int) {
 173             return forInt(constant.asInt());
 174         }
 175         if (constant.getJavaKind() == JavaKind.Object) {
 176             return new ConstantNode(constant, StampFactory.forConstant(constant, metaAccess), stableDimension, isDefaultStable);
 177         } else {
 178             assert stableDimension == 0;
 179             return createPrimitive(constant);
 180         }
 181     }
 182 
 183     public static ConstantNode forConstant(JavaConstant array, MetaAccessProvider metaAccess) {
 184         return forConstant(array, 0, false, metaAccess);
 185     }
 186 
 187     public static ConstantNode forConstant(Stamp stamp, Constant constant, MetaAccessProvider metaAccess, StructuredGraph graph) {
 188         return graph.unique(new ConstantNode(constant, stamp.constant(constant, metaAccess)));
 189     }
 190 
 191     public static ConstantNode forConstant(Stamp stamp, Constant constant, int stableDimension, boolean isDefaultStable, MetaAccessProvider metaAccess) {
 192         return new ConstantNode(constant, stamp.constant(constant, metaAccess), stableDimension, isDefaultStable);
 193     }
 194 
 195     public static ConstantNode forConstant(Stamp stamp, Constant constant, MetaAccessProvider metaAccess) {
 196         return new ConstantNode(constant, stamp.constant(constant, metaAccess));
 197     }
 198 
 199     /**
 200      * Returns a node for a Java primitive.
 201      */
 202     public static ConstantNode forPrimitive(JavaConstant constant, StructuredGraph graph) {
 203         assert constant.getJavaKind() != JavaKind.Object;
 204         return forConstant(constant, null, graph);
 205     }
 206 
 207     /**
 208      * Returns a node for a Java primitive.
 209      */
 210     public static ConstantNode forPrimitive(JavaConstant constant) {
 211         assert constant.getJavaKind() != JavaKind.Object;
 212         return forConstant(constant, null);
 213     }
 214 
 215     /**
 216      * Returns a node for a primitive of a given type.
 217      */
 218     public static ConstantNode forPrimitive(Stamp stamp, JavaConstant constant, StructuredGraph graph) {
 219         if (stamp instanceof IntegerStamp) {
 220             assert constant.getJavaKind().isNumericInteger() && stamp.getStackKind() == constant.getJavaKind().getStackKind();
 221             IntegerStamp istamp = (IntegerStamp) stamp;
 222             return forIntegerBits(istamp.getBits(), constant, graph);
 223         } else {
 224             assert constant.getJavaKind().isNumericFloat() && stamp.getStackKind() == constant.getJavaKind();
 225             return forPrimitive(constant, graph);
 226         }
 227     }
 228 
 229     /**
 230      * Returns a node for a primitive of a given type.
 231      */
 232     public static ConstantNode forPrimitive(Stamp stamp, Constant constant) {
 233         if (stamp instanceof IntegerStamp) {
 234             PrimitiveConstant primitive = (PrimitiveConstant) constant;
 235             assert primitive.getJavaKind().isNumericInteger() && stamp.getStackKind() == primitive.getJavaKind().getStackKind();
 236             IntegerStamp istamp = (IntegerStamp) stamp;
 237             return forIntegerBits(istamp.getBits(), primitive);
 238         } else if (stamp instanceof FloatStamp) {
 239             PrimitiveConstant primitive = (PrimitiveConstant) constant;
 240             assert primitive.getJavaKind().isNumericFloat() && stamp.getStackKind() == primitive.getJavaKind();
 241             return forConstant(primitive, null);
 242         } else {
 243             assert !(stamp instanceof AbstractObjectStamp);
 244             return new ConstantNode(constant, stamp.constant(constant, null));
 245         }
 246     }
 247 
 248     /**
 249      * Returns a node for a double constant.
 250      *
 251      * @param d the double value for which to create the instruction
 252      * @return a node for a double constant
 253      */
 254     public static ConstantNode forDouble(double d, StructuredGraph graph) {
 255         return unique(graph, createPrimitive(JavaConstant.forDouble(d)));
 256     }
 257 
 258     /**
 259      * Returns a node for a double constant.
 260      *
 261      * @param d the double value for which to create the instruction
 262      * @return a node for a double constant
 263      */
 264     public static ConstantNode forDouble(double d) {
 265         return createPrimitive(JavaConstant.forDouble(d));
 266     }
 267 
 268     /**
 269      * Returns a node for a float constant.
 270      *
 271      * @param f the float value for which to create the instruction
 272      * @return a node for a float constant
 273      */
 274     public static ConstantNode forFloat(float f, StructuredGraph graph) {
 275         return unique(graph, createPrimitive(JavaConstant.forFloat(f)));
 276     }
 277 
 278     /**
 279      * Returns a node for a float constant.
 280      *
 281      * @param f the float value for which to create the instruction
 282      * @return a node for a float constant
 283      */
 284     public static ConstantNode forFloat(float f) {
 285         return createPrimitive(JavaConstant.forFloat(f));
 286     }
 287 
 288     /**
 289      * Returns a node for an long constant.
 290      *
 291      * @param i the long value for which to create the instruction
 292      * @return a node for an long constant
 293      */
 294     public static ConstantNode forLong(long i, StructuredGraph graph) {
 295         return unique(graph, createPrimitive(JavaConstant.forLong(i)));
 296     }
 297 
 298     /**
 299      * Returns a node for an long constant.
 300      *
 301      * @param i the long value for which to create the instruction
 302      * @return a node for an long constant
 303      */
 304     public static ConstantNode forLong(long i) {
 305         return createPrimitive(JavaConstant.forLong(i));
 306     }
 307 
 308     /**
 309      * Returns a node for an integer constant.
 310      *
 311      * @param i the integer value for which to create the instruction
 312      * @return a node for an integer constant
 313      */
 314     public static ConstantNode forInt(int i, StructuredGraph graph) {
 315         return unique(graph, createPrimitive(JavaConstant.forInt(i)));
 316     }
 317 
 318     /**
 319      * Returns a node for an integer constant.
 320      *
 321      * @param i the integer value for which to create the instruction
 322      * @return a node for an integer constant
 323      */
 324     public static ConstantNode forInt(int i) {
 325         return createPrimitive(JavaConstant.forInt(i));
 326     }
 327 
 328     /**
 329      * Returns a node for a boolean constant.
 330      *
 331      * @param i the boolean value for which to create the instruction
 332      * @return a node representing the boolean
 333      */
 334     public static ConstantNode forBoolean(boolean i, StructuredGraph graph) {
 335         return unique(graph, createPrimitive(JavaConstant.forInt(i ? 1 : 0)));
 336     }
 337 
 338     /**
 339      * Returns a node for a boolean constant.
 340      *
 341      * @param i the boolean value for which to create the instruction
 342      * @return a node representing the boolean
 343      */
 344     public static ConstantNode forBoolean(boolean i) {
 345         return createPrimitive(JavaConstant.forInt(i ? 1 : 0));
 346     }
 347 
 348     /**
 349      * Returns a node for a byte constant.
 350      *
 351      * @param i the byte value for which to create the instruction
 352      * @return a node representing the byte
 353      */
 354     public static ConstantNode forByte(byte i, StructuredGraph graph) {
 355         return unique(graph, createPrimitive(JavaConstant.forInt(i)));
 356     }
 357 
 358     /**
 359      * Returns a node for a char constant.
 360      *
 361      * @param i the char value for which to create the instruction
 362      * @return a node representing the char
 363      */
 364     public static ConstantNode forChar(char i, StructuredGraph graph) {
 365         return unique(graph, createPrimitive(JavaConstant.forInt(i)));
 366     }
 367 
 368     /**
 369      * Returns a node for a short constant.
 370      *
 371      * @param i the short value for which to create the instruction
 372      * @return a node representing the short
 373      */
 374     public static ConstantNode forShort(short i, StructuredGraph graph) {
 375         return unique(graph, createPrimitive(JavaConstant.forInt(i)));
 376     }
 377 
 378     private static ConstantNode unique(StructuredGraph graph, ConstantNode node) {
 379         return graph.unique(node);
 380     }
 381 
 382     private static ConstantNode forIntegerBits(int bits, JavaConstant constant, StructuredGraph graph) {
 383         long value = constant.asLong();
 384         long bounds = CodeUtil.signExtend(value, bits);
 385         return unique(graph, new ConstantNode(constant, StampFactory.forInteger(bits, bounds, bounds)));
 386     }
 387 
 388     /**
 389      * Returns a node for a constant integer that's not directly representable as Java primitive
 390      * (e.g. short).
 391      */
 392     public static ConstantNode forIntegerBits(int bits, long value, StructuredGraph graph) {
 393         return forIntegerBits(bits, JavaConstant.forPrimitiveInt(bits, value), graph);
 394     }
 395 
 396     private static ConstantNode forIntegerBits(int bits, JavaConstant constant) {
 397         long value = constant.asLong();
 398         long bounds = CodeUtil.signExtend(value, bits);
 399         return new ConstantNode(constant, StampFactory.forInteger(bits, bounds, bounds));
 400     }
 401 
 402     /**
 403      * Returns a node for a constant integer that's not directly representable as Java primitive
 404      * (e.g. short).
 405      */
 406     public static ConstantNode forIntegerBits(int bits, long value) {
 407         return forIntegerBits(bits, JavaConstant.forPrimitiveInt(bits, value));
 408     }
 409 
 410     /**
 411      * Returns a node for a constant integer that's compatible to a given stamp.
 412      */
 413     public static ConstantNode forIntegerStamp(Stamp stamp, long value, StructuredGraph graph) {
 414         if (stamp instanceof IntegerStamp) {
 415             IntegerStamp intStamp = (IntegerStamp) stamp;
 416             return forIntegerBits(intStamp.getBits(), value, graph);
 417         } else {
 418             return forIntegerKind(stamp.getStackKind(), value, graph);
 419         }
 420     }
 421 
 422     /**
 423      * Returns a node for a constant integer that's compatible to a given stamp.
 424      */
 425     public static ConstantNode forIntegerStamp(Stamp stamp, long value) {
 426         if (stamp instanceof IntegerStamp) {
 427             IntegerStamp intStamp = (IntegerStamp) stamp;
 428             return forIntegerBits(intStamp.getBits(), value);
 429         } else {
 430             return forIntegerKind(stamp.getStackKind(), value);
 431         }
 432     }
 433 
 434     public static ConstantNode forIntegerKind(JavaKind kind, long value, StructuredGraph graph) {
 435         switch (kind) {
 436             case Byte:
 437             case Short:
 438             case Int:
 439                 return ConstantNode.forInt((int) value, graph);
 440             case Long:
 441                 return ConstantNode.forLong(value, graph);
 442             default:
 443                 throw GraalError.shouldNotReachHere("unknown kind " + kind);
 444         }
 445     }
 446 
 447     public static ConstantNode forIntegerKind(JavaKind kind, long value) {
 448         switch (kind) {
 449             case Byte:
 450             case Short:
 451             case Int:
 452                 return createPrimitive(JavaConstant.forInt((int) value));
 453             case Long:
 454                 return createPrimitive(JavaConstant.forLong(value));
 455             default:
 456                 throw GraalError.shouldNotReachHere("unknown kind " + kind);
 457         }
 458     }
 459 
 460     public static ConstantNode forFloatingKind(JavaKind kind, double value, StructuredGraph graph) {
 461         switch (kind) {
 462             case Float:
 463                 return ConstantNode.forFloat((float) value, graph);
 464             case Double:
 465                 return ConstantNode.forDouble(value, graph);
 466             default:
 467                 throw GraalError.shouldNotReachHere("unknown kind " + kind);
 468         }
 469     }
 470 
 471     public static ConstantNode forFloatingKind(JavaKind kind, double value) {
 472         switch (kind) {
 473             case Float:
 474                 return ConstantNode.forFloat((float) value);
 475             case Double:
 476                 return ConstantNode.forDouble(value);
 477             default:
 478                 throw GraalError.shouldNotReachHere("unknown kind " + kind);
 479         }
 480     }
 481 
 482     /**
 483      * Returns a node for a constant double that's compatible to a given stamp.
 484      */
 485     public static ConstantNode forFloatingStamp(Stamp stamp, double value, StructuredGraph graph) {
 486         return forFloatingKind(stamp.getStackKind(), value, graph);
 487     }
 488 
 489     /**
 490      * Returns a node for a constant double that's compatible to a given stamp.
 491      */
 492     public static ConstantNode forFloatingStamp(Stamp stamp, double value) {
 493         return forFloatingKind(stamp.getStackKind(), value);
 494     }
 495 
 496     public static ConstantNode defaultForKind(JavaKind kind, StructuredGraph graph) {
 497         return unique(graph, defaultForKind(kind));
 498     }
 499 
 500     public static ConstantNode defaultForKind(JavaKind kind) {
 501         switch (kind) {
 502             case Boolean:
 503             case Byte:
 504             case Char:
 505             case Short:
 506             case Int:
 507                 return ConstantNode.forInt(0);
 508             case Double:
 509                 return ConstantNode.forDouble(0.0);
 510             case Float:
 511                 return ConstantNode.forFloat(0.0f);
 512             case Long:
 513                 return ConstantNode.forLong(0L);
 514             case Object:
 515                 return ConstantNode.forConstant(JavaConstant.NULL_POINTER, null);
 516             default:
 517                 return null;
 518         }
 519     }
 520 
 521     @Override
 522     public Map<Object, Object> getDebugProperties(Map<Object, Object> map) {
 523         Map<Object, Object> properties = super.getDebugProperties(map);
 524         properties.put("rawvalue", value.toValueString());
 525         properties.put("stampKind", stamp.unrestricted().toString());
 526         return properties;
 527     }
 528 
 529     @Override
 530     public String toString(Verbosity verbosity) {
 531         if (verbosity == Verbosity.Name) {
 532             return super.toString(Verbosity.Name) + "(" + value.toValueString() + ", " + stamp(NodeView.DEFAULT).unrestricted().toString() + ")";
 533         } else {
 534             return super.toString(verbosity);
 535         }
 536     }
 537 
 538     @Override
 539     public ValueNode findLength(FindLengthMode mode, ConstantReflectionProvider constantReflection) {
 540         if (constantReflection == null || !(value instanceof JavaConstant) || ((JavaConstant) value).isNull()) {
 541             return null;
 542         }
 543         Integer length = constantReflection.readArrayLength((JavaConstant) value);
 544         if (length == null) {
 545             return null;
 546         }
 547         return ConstantNode.forInt(length);
 548     }
 549 }