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