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