001/*
002 * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023//JaCoCo Exclude
024package com.oracle.graal.nodes.java;
025
026import jdk.internal.jvmci.meta.*;
027
028import com.oracle.graal.compiler.common.type.*;
029import com.oracle.graal.graph.*;
030import com.oracle.graal.graph.spi.*;
031import com.oracle.graal.nodeinfo.*;
032import com.oracle.graal.nodes.*;
033
034/**
035 * The {@code DynamicNewArrayNode} is used for allocation of arrays when the type is not a
036 * compile-time constant.
037 */
038@NodeInfo
039public class DynamicNewArrayNode extends AbstractNewArrayNode implements Canonicalizable {
040    public static final NodeClass<DynamicNewArrayNode> TYPE = NodeClass.create(DynamicNewArrayNode.class);
041
042    @Input ValueNode elementType;
043
044    /**
045     * A non-null value indicating the worst case element type. Mainly useful for distinguishing
046     * Object arrays from primitive arrays.
047     */
048    protected final Kind knownElementKind;
049
050    public DynamicNewArrayNode(ValueNode elementType, ValueNode length, boolean fillContents) {
051        this(TYPE, elementType, length, fillContents, null, null, null);
052    }
053
054    public DynamicNewArrayNode(@InjectedNodeParameter MetaAccessProvider metaAccess, ValueNode elementType, ValueNode length, boolean fillContents, Kind knownElementKind) {
055        this(TYPE, elementType, length, fillContents, knownElementKind, null, metaAccess);
056    }
057
058    private static Stamp computeStamp(Kind knownElementKind, MetaAccessProvider metaAccess) {
059        if (knownElementKind != null && metaAccess != null) {
060            ResolvedJavaType arrayType = metaAccess.lookupJavaType(knownElementKind == Kind.Object ? Object.class : knownElementKind.toJavaClass()).getArrayClass();
061            return StampFactory.declaredNonNull(arrayType);
062        }
063        return StampFactory.objectNonNull();
064    }
065
066    protected DynamicNewArrayNode(NodeClass<? extends DynamicNewArrayNode> c, ValueNode elementType, ValueNode length, boolean fillContents, Kind knownElementKind, FrameState stateBefore,
067                    MetaAccessProvider metaAccess) {
068        super(c, computeStamp(knownElementKind, metaAccess), length, fillContents, stateBefore);
069        this.elementType = elementType;
070        this.knownElementKind = knownElementKind;
071        assert knownElementKind != Kind.Void && knownElementKind != Kind.Illegal;
072    }
073
074    public ValueNode getElementType() {
075        return elementType;
076    }
077
078    public Kind getKnownElementKind() {
079        return knownElementKind;
080    }
081
082    @Override
083    public void simplify(SimplifierTool tool) {
084        /*
085         * Do not call the super implementation: we must not eliminate unused allocations because
086         * throwing a NullPointerException or IllegalArgumentException is a possible side effect of
087         * an unused allocation.
088         */
089    }
090
091    @Override
092    public Node canonical(CanonicalizerTool tool) {
093        if (elementType.isConstant()) {
094            ResolvedJavaType type = tool.getConstantReflection().asJavaType(elementType.asConstant());
095            if (type != null && !throwsIllegalArgumentException(type)) {
096                return createNewArrayNode(type);
097            }
098        }
099        return this;
100    }
101
102    /** Hook for subclasses to instantiate a subclass of {@link NewArrayNode}. */
103    protected NewArrayNode createNewArrayNode(ResolvedJavaType type) {
104        return new NewArrayNode(type, length(), fillContents(), stateBefore());
105    }
106
107    public static boolean throwsIllegalArgumentException(Class<?> elementType) {
108        return elementType == void.class;
109    }
110
111    public static boolean throwsIllegalArgumentException(ResolvedJavaType elementType) {
112        return elementType.getKind() == Kind.Void;
113    }
114
115    @NodeIntrinsic
116    private static native Object newArray(Class<?> componentType, int length, @ConstantNodeParameter boolean fillContents, @ConstantNodeParameter Kind knownElementKind);
117
118    public static Object newArray(Class<?> componentType, int length, Kind knownElementKind) {
119        return newArray(componentType, length, true, knownElementKind);
120    }
121
122    public static Object newUninitializedArray(Class<?> componentType, int length, Kind knownElementKind) {
123        return newArray(componentType, length, false, knownElementKind);
124    }
125
126}