1 /*
   2  * Copyright (c) 2013, 2015, 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 //JaCoCo Exclude
  24 
  25 
  26 package org.graalvm.compiler.nodes.java;
  27 
  28 import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
  29 
  30 import org.graalvm.compiler.core.common.type.Stamp;
  31 import org.graalvm.compiler.core.common.type.StampFactory;
  32 import org.graalvm.compiler.core.common.type.TypeReference;
  33 import org.graalvm.compiler.graph.Node;
  34 import org.graalvm.compiler.graph.NodeClass;
  35 import org.graalvm.compiler.graph.spi.Canonicalizable;
  36 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
  37 import org.graalvm.compiler.nodeinfo.NodeInfo;
  38 import org.graalvm.compiler.nodes.FrameState;
  39 import org.graalvm.compiler.nodes.ValueNode;
  40 
  41 import jdk.vm.ci.meta.JavaKind;
  42 import jdk.vm.ci.meta.MetaAccessProvider;
  43 import jdk.vm.ci.meta.ResolvedJavaType;
  44 
  45 /**
  46  * The {@code DynamicNewArrayNode} is used for allocation of arrays when the type is not a
  47  * compile-time constant.
  48  */
  49 @NodeInfo
  50 public class DynamicNewArrayNode extends AbstractNewArrayNode implements Canonicalizable {
  51     public static final NodeClass<DynamicNewArrayNode> TYPE = NodeClass.create(DynamicNewArrayNode.class);
  52 
  53     @Input ValueNode elementType;
  54 
  55     /**
  56      * Class pointer to void.class needs to be exposed earlier than this node is lowered so that it
  57      * can be replaced by the AOT machinery. If it's not needed for lowering this input can be
  58      * ignored.
  59      */
  60     @OptionalInput ValueNode voidClass;
  61 
  62     /**
  63      * A non-null value indicating the worst case element type. Mainly useful for distinguishing
  64      * Object arrays from primitive arrays.
  65      */
  66     protected final JavaKind knownElementKind;
  67 
  68     public DynamicNewArrayNode(ValueNode elementType, ValueNode length, boolean fillContents) {
  69         this(TYPE, elementType, length, fillContents, null, null, null);
  70     }
  71 
  72     public DynamicNewArrayNode(@InjectedNodeParameter MetaAccessProvider metaAccess, ValueNode elementType, ValueNode length, boolean fillContents, JavaKind knownElementKind) {
  73         this(TYPE, elementType, length, fillContents, knownElementKind, null, metaAccess);
  74     }
  75 
  76     private static Stamp computeStamp(JavaKind knownElementKind, MetaAccessProvider metaAccess) {
  77         if (knownElementKind != null && metaAccess != null) {
  78             ResolvedJavaType arrayType = metaAccess.lookupJavaType(knownElementKind == JavaKind.Object ? Object.class : knownElementKind.toJavaClass()).getArrayClass();
  79             return StampFactory.objectNonNull(TypeReference.createWithoutAssumptions(arrayType));
  80         }
  81         return StampFactory.objectNonNull();
  82     }
  83 
  84     protected DynamicNewArrayNode(NodeClass<? extends DynamicNewArrayNode> c, ValueNode elementType, ValueNode length, boolean fillContents, JavaKind knownElementKind, FrameState stateBefore,
  85                     MetaAccessProvider metaAccess) {
  86         super(c, computeStamp(knownElementKind, metaAccess), length, fillContents, stateBefore);
  87         this.elementType = elementType;
  88         this.knownElementKind = knownElementKind;
  89         assert knownElementKind != JavaKind.Void && knownElementKind != JavaKind.Illegal;
  90     }
  91 
  92     public ValueNode getElementType() {
  93         return elementType;
  94     }
  95 
  96     public JavaKind getKnownElementKind() {
  97         return knownElementKind;
  98     }
  99 
 100     @Override
 101     public Node canonical(CanonicalizerTool tool) {
 102         if (elementType.isConstant()) {
 103             if (GeneratePIC.getValue(tool.getOptions())) {
 104                 // Can't fold for AOT, because the resulting NewArrayNode will be missing its
 105                 // ResolveConstantNode for the array class.
 106                 return this;
 107             }
 108             ResolvedJavaType type = tool.getConstantReflection().asJavaType(elementType.asConstant());
 109             if (type != null && !throwsIllegalArgumentException(type)) {
 110                 return createNewArrayNode(type);
 111             }
 112         }
 113         return this;
 114     }
 115 
 116     /** Hook for subclasses to instantiate a subclass of {@link NewArrayNode}. */
 117     protected NewArrayNode createNewArrayNode(ResolvedJavaType type) {
 118         return new NewArrayNode(type, length(), fillContents(), stateBefore());
 119     }
 120 
 121     public static boolean throwsIllegalArgumentException(Class<?> elementType, Class<?> voidClass) {
 122         return elementType == voidClass;
 123     }
 124 
 125     public static boolean throwsIllegalArgumentException(ResolvedJavaType elementType) {
 126         return elementType.getJavaKind() == JavaKind.Void;
 127     }
 128 
 129     @NodeIntrinsic
 130     private static native Object newArray(Class<?> componentType, int length, @ConstantNodeParameter boolean fillContents);
 131 
 132     public static Object newArray(Class<?> componentType, int length) {
 133         return newArray(componentType, length, true);
 134     }
 135 
 136     @NodeIntrinsic
 137     private static native Object newArray(Class<?> componentType, int length, @ConstantNodeParameter boolean fillContents, @ConstantNodeParameter JavaKind knownElementKind);
 138 
 139     public static Object newArray(Class<?> componentType, int length, JavaKind knownElementKind) {
 140         return newArray(componentType, length, true, knownElementKind);
 141     }
 142 
 143     public static Object newUninitializedArray(Class<?> componentType, int length, JavaKind knownElementKind) {
 144         return newArray(componentType, length, false, knownElementKind);
 145     }
 146 
 147     public ValueNode getVoidClass() {
 148         return voidClass;
 149     }
 150 
 151     public void setVoidClass(ValueNode newVoidClass) {
 152         updateUsages(voidClass, newVoidClass);
 153         voidClass = newVoidClass;
 154     }
 155 }