/*
 * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */


package org.graalvm.compiler.nodes;

import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;

import java.util.Map;

import org.graalvm.compiler.core.common.LIRKind;
import org.graalvm.compiler.core.common.type.AbstractObjectStamp;
import org.graalvm.compiler.core.common.type.FloatStamp;
import org.graalvm.compiler.core.common.type.IntegerStamp;
import org.graalvm.compiler.core.common.type.Stamp;
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.graph.iterators.NodeIterable;
import org.graalvm.compiler.lir.ConstantValue;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodeinfo.Verbosity;
import org.graalvm.compiler.nodes.calc.FloatingNode;
import org.graalvm.compiler.nodes.spi.ArrayLengthProvider;
import org.graalvm.compiler.nodes.spi.LIRLowerable;
import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;

import jdk.vm.ci.code.CodeUtil;
import jdk.vm.ci.meta.Constant;
import jdk.vm.ci.meta.ConstantReflectionProvider;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.MetaAccessProvider;
import jdk.vm.ci.meta.PrimitiveConstant;
import jdk.vm.ci.meta.ResolvedJavaType;

The ConstantNode represents a constant.
/** * The {@code ConstantNode} represents a {@link Constant constant}. */
@NodeInfo(nameTemplate = "C({p#rawvalue}) {p#stampKind}", cycles = CYCLES_0, size = SIZE_1) public final class ConstantNode extends FloatingNode implements LIRLowerable, ArrayLengthProvider { public static final NodeClass<ConstantNode> TYPE = NodeClass.create(ConstantNode.class); protected final Constant value; private final int stableDimension; private final boolean isDefaultStable; private static ConstantNode createPrimitive(JavaConstant value) { assert value.getJavaKind() != JavaKind.Object; return new ConstantNode(value, StampFactory.forConstant(value)); }
Constructs a new node representing the specified constant.
Params:
  • value – the constant
/** * Constructs a new node representing the specified constant. * * @param value the constant */
public ConstantNode(Constant value, Stamp stamp) { this(value, stamp, 0, false); } private ConstantNode(Constant value, Stamp stamp, int stableDimension, boolean isDefaultStable) { super(TYPE, stamp); assert stamp != null && stamp.isCompatible(value) : stamp + " " + value; this.value = value; this.stableDimension = stableDimension; if (stableDimension == 0) { /* * Ensure that isDefaultStable has a canonical value to avoid having two constant nodes * that only differ in this field. The value of isDefaultStable is only used when we * have a stable array dimension. */ this.isDefaultStable = false; } else { this.isDefaultStable = isDefaultStable; } } public ConstantNode(@InjectedNodeParameter Stamp stamp, @InjectedNodeParameter ConstantReflectionProvider constantReflection, @ConstantNodeParameter ResolvedJavaType type) { this(constantReflection.asJavaClass(type), stamp); }
Returns:the constant value represented by this node
/** * @return the constant value represented by this node */
public Constant getValue() { return value; }
Returns:the number of stable dimensions if this is a stable array, otherwise 0
/** * @return the number of stable dimensions if this is a stable array, otherwise 0 */
public int getStableDimension() { return stableDimension; }
Returns:true if this is a stable array and the default elements are considered stable
/** * @return true if this is a stable array and the default elements are considered stable */
public boolean isDefaultStable() { return isDefaultStable; }
Gathers all the ConstantNodes that are inputs to the live nodes in a given graph.
/** * Gathers all the {@link ConstantNode}s that are inputs to the * {@linkplain StructuredGraph#getNodes() live nodes} in a given graph. */
public static NodeIterable<ConstantNode> getConstantNodes(StructuredGraph graph) { return graph.getNodes().filter(ConstantNode.class); }
Replaces this node at its usages with another node.
/** * Replaces this node at its usages with another node. */
public void replace(StructuredGraph graph, Node replacement) { assert graph == graph(); replaceAtUsagesAndDelete(replacement); } @Override public void generate(NodeLIRBuilderTool gen) { LIRKind kind = gen.getLIRGeneratorTool().getLIRKind(stamp(NodeView.DEFAULT)); if (onlyUsedInVirtualState()) { gen.setResult(this, new ConstantValue(kind, value)); } else { gen.setResult(this, gen.getLIRGeneratorTool().emitConstant(kind, value)); } } private boolean onlyUsedInVirtualState() { for (Node n : this.usages()) { if (n instanceof VirtualState) { // Only virtual usage. } else { return false; } } return true; } public static ConstantNode forConstant(JavaConstant constant, MetaAccessProvider metaAccess, StructuredGraph graph) { if (constant.getJavaKind().getStackKind() == JavaKind.Int && constant.getJavaKind() != JavaKind.Int) { return forInt(constant.asInt(), graph); } if (constant.getJavaKind() == JavaKind.Object) { return unique(graph, new ConstantNode(constant, StampFactory.forConstant(constant, metaAccess))); } else { return unique(graph, createPrimitive(constant)); } } public static ConstantNode forConstant(JavaConstant constant, int stableDimension, boolean isDefaultStable, MetaAccessProvider metaAccess) { if (constant.getJavaKind().getStackKind() == JavaKind.Int && constant.getJavaKind() != JavaKind.Int) { return forInt(constant.asInt()); } if (constant.getJavaKind() == JavaKind.Object) { return new ConstantNode(constant, StampFactory.forConstant(constant, metaAccess), stableDimension, isDefaultStable); } else { assert stableDimension == 0; return createPrimitive(constant); } } public static ConstantNode forConstant(JavaConstant array, MetaAccessProvider metaAccess) { return forConstant(array, 0, false, metaAccess); } public static ConstantNode forConstant(Stamp stamp, Constant constant, MetaAccessProvider metaAccess, StructuredGraph graph) { return graph.unique(new ConstantNode(constant, stamp.constant(constant, metaAccess))); } public static ConstantNode forConstant(Stamp stamp, Constant constant, int stableDimension, boolean isDefaultStable, MetaAccessProvider metaAccess) { return new ConstantNode(constant, stamp.constant(constant, metaAccess), stableDimension, isDefaultStable); } public static ConstantNode forConstant(Stamp stamp, Constant constant, MetaAccessProvider metaAccess) { return new ConstantNode(constant, stamp.constant(constant, metaAccess)); }
Returns a node for a Java primitive.
/** * Returns a node for a Java primitive. */
public static ConstantNode forPrimitive(JavaConstant constant, StructuredGraph graph) { assert constant.getJavaKind() != JavaKind.Object; return forConstant(constant, null, graph); }
Returns a node for a Java primitive.
/** * Returns a node for a Java primitive. */
public static ConstantNode forPrimitive(JavaConstant constant) { assert constant.getJavaKind() != JavaKind.Object; return forConstant(constant, null); }
Returns a node for a primitive of a given type.
/** * Returns a node for a primitive of a given type. */
public static ConstantNode forPrimitive(Stamp stamp, JavaConstant constant, StructuredGraph graph) { if (stamp instanceof IntegerStamp) { assert constant.getJavaKind().isNumericInteger() && stamp.getStackKind() == constant.getJavaKind().getStackKind(); IntegerStamp istamp = (IntegerStamp) stamp; return forIntegerBits(istamp.getBits(), constant, graph); } else { assert constant.getJavaKind().isNumericFloat() && stamp.getStackKind() == constant.getJavaKind(); return forPrimitive(constant, graph); } }
Returns a node for a primitive of a given type.
/** * Returns a node for a primitive of a given type. */
public static ConstantNode forPrimitive(Stamp stamp, Constant constant) { if (stamp instanceof IntegerStamp) { PrimitiveConstant primitive = (PrimitiveConstant) constant; assert primitive.getJavaKind().isNumericInteger() && stamp.getStackKind() == primitive.getJavaKind().getStackKind(); IntegerStamp istamp = (IntegerStamp) stamp; return forIntegerBits(istamp.getBits(), primitive); } else if (stamp instanceof FloatStamp) { PrimitiveConstant primitive = (PrimitiveConstant) constant; assert primitive.getJavaKind().isNumericFloat() && stamp.getStackKind() == primitive.getJavaKind(); return forConstant(primitive, null); } else { assert !(stamp instanceof AbstractObjectStamp); return new ConstantNode(constant, stamp.constant(constant, null)); } }
Returns a node for a double constant.
Params:
  • d – the double value for which to create the instruction
Returns:a node for a double constant
/** * Returns a node for a double constant. * * @param d the double value for which to create the instruction * @return a node for a double constant */
public static ConstantNode forDouble(double d, StructuredGraph graph) { return unique(graph, createPrimitive(JavaConstant.forDouble(d))); }
Returns a node for a double constant.
Params:
  • d – the double value for which to create the instruction
Returns:a node for a double constant
/** * Returns a node for a double constant. * * @param d the double value for which to create the instruction * @return a node for a double constant */
public static ConstantNode forDouble(double d) { return createPrimitive(JavaConstant.forDouble(d)); }
Returns a node for a float constant.
Params:
  • f – the float value for which to create the instruction
Returns:a node for a float constant
/** * Returns a node for a float constant. * * @param f the float value for which to create the instruction * @return a node for a float constant */
public static ConstantNode forFloat(float f, StructuredGraph graph) { return unique(graph, createPrimitive(JavaConstant.forFloat(f))); }
Returns a node for a float constant.
Params:
  • f – the float value for which to create the instruction
Returns:a node for a float constant
/** * Returns a node for a float constant. * * @param f the float value for which to create the instruction * @return a node for a float constant */
public static ConstantNode forFloat(float f) { return createPrimitive(JavaConstant.forFloat(f)); }
Returns a node for an long constant.
Params:
  • i – the long value for which to create the instruction
Returns:a node for an long constant
/** * Returns a node for an long constant. * * @param i the long value for which to create the instruction * @return a node for an long constant */
public static ConstantNode forLong(long i, StructuredGraph graph) { return unique(graph, createPrimitive(JavaConstant.forLong(i))); }
Returns a node for an long constant.
Params:
  • i – the long value for which to create the instruction
Returns:a node for an long constant
/** * Returns a node for an long constant. * * @param i the long value for which to create the instruction * @return a node for an long constant */
public static ConstantNode forLong(long i) { return createPrimitive(JavaConstant.forLong(i)); }
Returns a node for an integer constant.
Params:
  • i – the integer value for which to create the instruction
Returns:a node for an integer constant
/** * Returns a node for an integer constant. * * @param i the integer value for which to create the instruction * @return a node for an integer constant */
public static ConstantNode forInt(int i, StructuredGraph graph) { return unique(graph, createPrimitive(JavaConstant.forInt(i))); }
Returns a node for an integer constant.
Params:
  • i – the integer value for which to create the instruction
Returns:a node for an integer constant
/** * Returns a node for an integer constant. * * @param i the integer value for which to create the instruction * @return a node for an integer constant */
public static ConstantNode forInt(int i) { return createPrimitive(JavaConstant.forInt(i)); }
Returns a node for a boolean constant.
Params:
  • i – the boolean value for which to create the instruction
Returns:a node representing the boolean
/** * Returns a node for a boolean constant. * * @param i the boolean value for which to create the instruction * @return a node representing the boolean */
public static ConstantNode forBoolean(boolean i, StructuredGraph graph) { return unique(graph, createPrimitive(JavaConstant.forInt(i ? 1 : 0))); }
Returns a node for a boolean constant.
Params:
  • i – the boolean value for which to create the instruction
Returns:a node representing the boolean
/** * Returns a node for a boolean constant. * * @param i the boolean value for which to create the instruction * @return a node representing the boolean */
public static ConstantNode forBoolean(boolean i) { return createPrimitive(JavaConstant.forInt(i ? 1 : 0)); }
Returns a node for a byte constant.
Params:
  • i – the byte value for which to create the instruction
Returns:a node representing the byte
/** * Returns a node for a byte constant. * * @param i the byte value for which to create the instruction * @return a node representing the byte */
public static ConstantNode forByte(byte i, StructuredGraph graph) { return unique(graph, createPrimitive(JavaConstant.forInt(i))); }
Returns a node for a char constant.
Params:
  • i – the char value for which to create the instruction
Returns:a node representing the char
/** * Returns a node for a char constant. * * @param i the char value for which to create the instruction * @return a node representing the char */
public static ConstantNode forChar(char i, StructuredGraph graph) { return unique(graph, createPrimitive(JavaConstant.forInt(i))); }
Returns a node for a short constant.
Params:
  • i – the short value for which to create the instruction
Returns:a node representing the short
/** * Returns a node for a short constant. * * @param i the short value for which to create the instruction * @return a node representing the short */
public static ConstantNode forShort(short i, StructuredGraph graph) { return unique(graph, createPrimitive(JavaConstant.forInt(i))); } private static ConstantNode unique(StructuredGraph graph, ConstantNode node) { return graph.unique(node); } private static ConstantNode forIntegerBits(int bits, JavaConstant constant, StructuredGraph graph) { long value = constant.asLong(); long bounds = CodeUtil.signExtend(value, bits); return unique(graph, new ConstantNode(constant, StampFactory.forInteger(bits, bounds, bounds))); }
Returns a node for a constant integer that's not directly representable as Java primitive (e.g. short).
/** * Returns a node for a constant integer that's not directly representable as Java primitive * (e.g. short). */
public static ConstantNode forIntegerBits(int bits, long value, StructuredGraph graph) { return forIntegerBits(bits, JavaConstant.forPrimitiveInt(bits, value), graph); } private static ConstantNode forIntegerBits(int bits, JavaConstant constant) { long value = constant.asLong(); long bounds = CodeUtil.signExtend(value, bits); return new ConstantNode(constant, StampFactory.forInteger(bits, bounds, bounds)); }
Returns a node for a constant integer that's not directly representable as Java primitive (e.g. short).
/** * Returns a node for a constant integer that's not directly representable as Java primitive * (e.g. short). */
public static ConstantNode forIntegerBits(int bits, long value) { return forIntegerBits(bits, JavaConstant.forPrimitiveInt(bits, value)); }
Returns a node for a constant integer that's compatible to a given stamp.
/** * Returns a node for a constant integer that's compatible to a given stamp. */
public static ConstantNode forIntegerStamp(Stamp stamp, long value, StructuredGraph graph) { if (stamp instanceof IntegerStamp) { IntegerStamp intStamp = (IntegerStamp) stamp; return forIntegerBits(intStamp.getBits(), value, graph); } else { return forIntegerKind(stamp.getStackKind(), value, graph); } }
Returns a node for a constant integer that's compatible to a given stamp.
/** * Returns a node for a constant integer that's compatible to a given stamp. */
public static ConstantNode forIntegerStamp(Stamp stamp, long value) { if (stamp instanceof IntegerStamp) { IntegerStamp intStamp = (IntegerStamp) stamp; return forIntegerBits(intStamp.getBits(), value); } else { return forIntegerKind(stamp.getStackKind(), value); } } public static ConstantNode forIntegerKind(JavaKind kind, long value, StructuredGraph graph) { switch (kind) { case Byte: case Short: case Int: return ConstantNode.forInt((int) value, graph); case Long: return ConstantNode.forLong(value, graph); default: throw GraalError.shouldNotReachHere("unknown kind " + kind); } } public static ConstantNode forIntegerKind(JavaKind kind, long value) { switch (kind) { case Byte: case Short: case Int: return createPrimitive(JavaConstant.forInt((int) value)); case Long: return createPrimitive(JavaConstant.forLong(value)); default: throw GraalError.shouldNotReachHere("unknown kind " + kind); } } public static ConstantNode forFloatingKind(JavaKind kind, double value, StructuredGraph graph) { switch (kind) { case Float: return ConstantNode.forFloat((float) value, graph); case Double: return ConstantNode.forDouble(value, graph); default: throw GraalError.shouldNotReachHere("unknown kind " + kind); } } public static ConstantNode forFloatingKind(JavaKind kind, double value) { switch (kind) { case Float: return ConstantNode.forFloat((float) value); case Double: return ConstantNode.forDouble(value); default: throw GraalError.shouldNotReachHere("unknown kind " + kind); } }
Returns a node for a constant double that's compatible to a given stamp.
/** * Returns a node for a constant double that's compatible to a given stamp. */
public static ConstantNode forFloatingStamp(Stamp stamp, double value, StructuredGraph graph) { return forFloatingKind(stamp.getStackKind(), value, graph); }
Returns a node for a constant double that's compatible to a given stamp.
/** * Returns a node for a constant double that's compatible to a given stamp. */
public static ConstantNode forFloatingStamp(Stamp stamp, double value) { return forFloatingKind(stamp.getStackKind(), value); } public static ConstantNode defaultForKind(JavaKind kind, StructuredGraph graph) { return unique(graph, defaultForKind(kind)); } public static ConstantNode defaultForKind(JavaKind kind) { switch (kind) { case Boolean: case Byte: case Char: case Short: case Int: return ConstantNode.forInt(0); case Double: return ConstantNode.forDouble(0.0); case Float: return ConstantNode.forFloat(0.0f); case Long: return ConstantNode.forLong(0L); case Object: return ConstantNode.forConstant(JavaConstant.NULL_POINTER, null); default: return null; } } @Override public Map<Object, Object> getDebugProperties(Map<Object, Object> map) { Map<Object, Object> properties = super.getDebugProperties(map); properties.put("rawvalue", value.toValueString()); properties.put("stampKind", stamp.unrestricted().toString()); return properties; } @Override public String toString(Verbosity verbosity) { if (verbosity == Verbosity.Name) { return super.toString(Verbosity.Name) + "(" + value.toValueString() + ", " + stamp(NodeView.DEFAULT).unrestricted().toString() + ")"; } else { return super.toString(verbosity); } } @Override public ValueNode findLength(FindLengthMode mode, ConstantReflectionProvider constantReflection) { if (constantReflection == null || !(value instanceof JavaConstant) || ((JavaConstant) value).isNull()) { return null; } Integer length = constantReflection.readArrayLength((JavaConstant) value); if (length == null) { return null; } return ConstantNode.forInt(length); } @NodeIntrinsic public static native Class<?> forClass(@ConstantNodeParameter ResolvedJavaType type); }