1 /*
   2  * Copyright (c) 2011, 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 package org.graalvm.compiler.nodes.virtual;
  24 
  25 import java.nio.ByteOrder;
  26 
  27 import org.graalvm.compiler.graph.NodeClass;
  28 import org.graalvm.compiler.nodeinfo.NodeInfo;
  29 import org.graalvm.compiler.nodeinfo.Verbosity;
  30 import org.graalvm.compiler.nodes.ConstantNode;
  31 import org.graalvm.compiler.nodes.FixedNode;
  32 import org.graalvm.compiler.nodes.ValueNode;
  33 import org.graalvm.compiler.nodes.spi.ArrayLengthProvider;
  34 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
  35 
  36 import jdk.vm.ci.meta.JavaKind;
  37 import jdk.vm.ci.meta.ResolvedJavaType;
  38 import sun.misc.Unsafe;
  39 
  40 @NodeInfo(nameTemplate = "VirtualArray({p#objectId}) {p#componentType/s}[{p#length}]")
  41 public class VirtualArrayNode extends VirtualObjectNode implements ArrayLengthProvider {
  42 
  43     public static final NodeClass<VirtualArrayNode> TYPE = NodeClass.create(VirtualArrayNode.class);
  44     protected final ResolvedJavaType componentType;
  45     protected final int length;
  46 
  47     public VirtualArrayNode(ResolvedJavaType componentType, int length) {
  48         this(TYPE, componentType, length);
  49     }
  50 
  51     protected VirtualArrayNode(NodeClass<? extends VirtualObjectNode> c, ResolvedJavaType componentType, int length) {
  52         super(c, componentType.getArrayClass(), true);
  53         this.componentType = componentType;
  54         this.length = length;
  55     }
  56 
  57     @Override
  58     public ResolvedJavaType type() {
  59         return componentType.getArrayClass();
  60     }
  61 
  62     public ResolvedJavaType componentType() {
  63         return componentType;
  64     }
  65 
  66     @Override
  67     public int entryCount() {
  68         return length;
  69     }
  70 
  71     @Override
  72     public void generate(NodeLIRBuilderTool gen) {
  73         // nothing to do...
  74     }
  75 
  76     @Override
  77     public String toString(Verbosity verbosity) {
  78         if (verbosity == Verbosity.Name) {
  79             return super.toString(Verbosity.Name) + "(" + getObjectId() + ") " + componentType.getName() + "[" + length + "]";
  80         } else {
  81             return super.toString(verbosity);
  82         }
  83     }
  84 
  85     @Override
  86     public String entryName(int index) {
  87         return "[" + index + "]";
  88     }
  89 
  90     @Override
  91     public int entryIndexForOffset(long constantOffset, JavaKind expectedEntryKind) {
  92         return entryIndexForOffset(constantOffset, expectedEntryKind, componentType, length);
  93     }
  94 
  95     public static int entryIndexForOffset(long constantOffset, JavaKind expectedEntryKind, ResolvedJavaType componentType, int length) {
  96         int baseOffset;
  97         int indexScale;
  98         switch (componentType.getJavaKind()) {
  99             case Boolean:
 100                 baseOffset = Unsafe.ARRAY_BOOLEAN_BASE_OFFSET;
 101                 indexScale = Unsafe.ARRAY_BOOLEAN_INDEX_SCALE;
 102                 break;
 103             case Byte:
 104                 baseOffset = Unsafe.ARRAY_BYTE_BASE_OFFSET;
 105                 indexScale = Unsafe.ARRAY_BYTE_INDEX_SCALE;
 106                 break;
 107             case Short:
 108                 baseOffset = Unsafe.ARRAY_SHORT_BASE_OFFSET;
 109                 indexScale = Unsafe.ARRAY_SHORT_INDEX_SCALE;
 110                 break;
 111             case Char:
 112                 baseOffset = Unsafe.ARRAY_CHAR_BASE_OFFSET;
 113                 indexScale = Unsafe.ARRAY_CHAR_INDEX_SCALE;
 114                 break;
 115             case Int:
 116                 baseOffset = Unsafe.ARRAY_INT_BASE_OFFSET;
 117                 indexScale = Unsafe.ARRAY_INT_INDEX_SCALE;
 118                 break;
 119             case Long:
 120                 baseOffset = Unsafe.ARRAY_LONG_BASE_OFFSET;
 121                 indexScale = Unsafe.ARRAY_LONG_INDEX_SCALE;
 122                 break;
 123             case Float:
 124                 baseOffset = Unsafe.ARRAY_FLOAT_BASE_OFFSET;
 125                 indexScale = Unsafe.ARRAY_FLOAT_INDEX_SCALE;
 126                 break;
 127             case Double:
 128                 baseOffset = Unsafe.ARRAY_DOUBLE_BASE_OFFSET;
 129                 indexScale = Unsafe.ARRAY_DOUBLE_INDEX_SCALE;
 130                 break;
 131             case Object:
 132                 baseOffset = Unsafe.ARRAY_OBJECT_BASE_OFFSET;
 133                 indexScale = Unsafe.ARRAY_OBJECT_INDEX_SCALE;
 134                 break;
 135             default:
 136                 return -1;
 137         }
 138         long offset;
 139         if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN && componentType.isPrimitive()) {
 140             // On big endian, we expect the value to be correctly aligned in memory
 141             int componentByteCount = componentType.getJavaKind().getByteCount();
 142             offset = constantOffset - (componentByteCount - Math.min(componentByteCount, 4 + expectedEntryKind.getByteCount()));
 143         } else {
 144             offset = constantOffset;
 145         }
 146         long index = offset - baseOffset;
 147         if (index % indexScale != 0) {
 148             return -1;
 149         }
 150         long elementIndex = index / indexScale;
 151         if (elementIndex < 0 || elementIndex >= length) {
 152             return -1;
 153         }
 154         return (int) elementIndex;
 155     }
 156 
 157     @Override
 158     public JavaKind entryKind(int index) {
 159         assert index >= 0 && index < length;
 160         return componentType.getJavaKind();
 161     }
 162 
 163     @Override
 164     public VirtualArrayNode duplicate() {
 165         return new VirtualArrayNode(componentType, length);
 166     }
 167 
 168     @Override
 169     public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, LockState locks) {
 170         return new AllocatedObjectNode(this);
 171     }
 172 
 173     @Override
 174     public ValueNode length() {
 175         return ConstantNode.forInt(length);
 176     }
 177 }