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