1 /*
   2  * Copyright (c) 2011, 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  */
  23 package jdk.vm.ci.hotspot;
  24 
  25 import java.lang.reflect.Array;
  26 import java.util.Objects;
  27 
  28 import jdk.internal.vm.annotation.Stable;
  29 import jdk.vm.ci.common.JVMCIError;
  30 import jdk.vm.ci.meta.Constant;
  31 import jdk.vm.ci.meta.ConstantReflectionProvider;
  32 import jdk.vm.ci.meta.JavaConstant;
  33 import jdk.vm.ci.meta.JavaKind;
  34 import jdk.vm.ci.meta.MemoryAccessProvider;
  35 import jdk.vm.ci.meta.MethodHandleAccessProvider;
  36 import jdk.vm.ci.meta.ResolvedJavaField;
  37 import jdk.vm.ci.meta.ResolvedJavaType;
  38 
  39 /**
  40  * HotSpot implementation of {@link ConstantReflectionProvider}.
  41  */
  42 public class HotSpotConstantReflectionProvider implements ConstantReflectionProvider {
  43 
  44     protected final HotSpotJVMCIRuntimeProvider runtime;
  45     protected final HotSpotMethodHandleAccessProvider methodHandleAccess;
  46     protected final HotSpotMemoryAccessProviderImpl memoryAccess;
  47 
  48     public HotSpotConstantReflectionProvider(HotSpotJVMCIRuntimeProvider runtime) {
  49         this.runtime = runtime;
  50         this.methodHandleAccess = new HotSpotMethodHandleAccessProvider(this);
  51         this.memoryAccess = new HotSpotMemoryAccessProviderImpl(runtime);
  52     }
  53 
  54     public MethodHandleAccessProvider getMethodHandleAccess() {
  55         return methodHandleAccess;
  56     }
  57 
  58     @Override
  59     public MemoryAccessProvider getMemoryAccessProvider() {
  60         return memoryAccess;
  61     }
  62 
  63     @Override
  64     public Boolean constantEquals(Constant x, Constant y) {
  65         if (x == y) {
  66             return true;
  67         } else if (x instanceof HotSpotObjectConstantImpl) {
  68             return y instanceof HotSpotObjectConstantImpl && ((HotSpotObjectConstantImpl) x).object() == ((HotSpotObjectConstantImpl) y).object();
  69         } else {
  70             return Objects.equals(x, y);
  71         }
  72     }
  73 
  74     @Override
  75     public Integer readArrayLength(JavaConstant array) {
  76         if (array == null || array.getJavaKind() != JavaKind.Object || array.isNull()) {
  77             return null;
  78         }
  79 
  80         Object arrayObject = ((HotSpotObjectConstantImpl) array).object();
  81         if (!arrayObject.getClass().isArray()) {
  82             return null;
  83         }
  84         return Array.getLength(arrayObject);
  85     }
  86 
  87     @Override
  88     public JavaConstant readArrayElement(JavaConstant array, int index) {
  89         if (array == null || array.getJavaKind() != JavaKind.Object || array.isNull()) {
  90             return null;
  91         }
  92         Object a = ((HotSpotObjectConstantImpl) array).object();
  93 
  94         if (!a.getClass().isArray() || index < 0 || index >= Array.getLength(a)) {
  95             return null;
  96         }
  97 
  98         if (a instanceof Object[]) {
  99             Object element = ((Object[]) a)[index];
 100             return HotSpotObjectConstantImpl.forObject(element);
 101         } else {
 102             return JavaConstant.forBoxedPrimitive(Array.get(a, index));
 103         }
 104     }
 105 
 106     /**
 107      * Check if the constant is a boxed value that is guaranteed to be cached by the platform.
 108      * Otherwise the generated code might be the only reference to the boxed value and since object
 109      * references from nmethods are weak this can cause GC problems.
 110      *
 111      * @param source
 112      * @return true if the box is cached
 113      */
 114     private static boolean isBoxCached(JavaConstant source) {
 115         switch (source.getJavaKind()) {
 116             case Boolean:
 117                 return true;
 118             case Char:
 119                 return source.asInt() <= 127;
 120             case Byte:
 121             case Short:
 122             case Int:
 123                 return source.asInt() >= -128 && source.asInt() <= 127;
 124             case Long:
 125                 return source.asLong() >= -128 && source.asLong() <= 127;
 126             case Float:
 127             case Double:
 128                 return false;
 129             default:
 130                 throw new IllegalArgumentException("unexpected kind " + source.getJavaKind());
 131         }
 132     }
 133 
 134     @Override
 135     public JavaConstant boxPrimitive(JavaConstant source) {
 136         if (source == null || !source.getJavaKind().isPrimitive() || !isBoxCached(source)) {
 137             return null;
 138         }
 139         return HotSpotObjectConstantImpl.forObject(source.asBoxedPrimitive());
 140     }
 141 
 142     @Override
 143     public JavaConstant unboxPrimitive(JavaConstant source) {
 144         if (source == null || !source.getJavaKind().isObject()) {
 145             return null;
 146         }
 147         if (source.isNull()) {
 148             return null;
 149         }
 150         return JavaConstant.forBoxedPrimitive(((HotSpotObjectConstantImpl) source).object());
 151     }
 152 
 153     public JavaConstant forString(String value) {
 154         return HotSpotObjectConstantImpl.forObject(value);
 155     }
 156 
 157     public JavaConstant forObject(Object value) {
 158         return HotSpotObjectConstantImpl.forObject(value);
 159     }
 160 
 161     @Override
 162     public ResolvedJavaType asJavaType(Constant constant) {
 163         if (constant instanceof HotSpotObjectConstant) {
 164             Object obj = ((HotSpotObjectConstantImpl) constant).object();
 165             if (obj instanceof Class) {
 166                 return runtime.getHostJVMCIBackend().getMetaAccess().lookupJavaType((Class<?>) obj);
 167             }
 168         }
 169         if (constant instanceof HotSpotMetaspaceConstant) {
 170             MetaspaceWrapperObject obj = HotSpotMetaspaceConstantImpl.getMetaspaceObject(constant);
 171             if (obj instanceof HotSpotResolvedObjectTypeImpl) {
 172                 return (ResolvedJavaType) obj;
 173             }
 174         }
 175         return null;
 176     }
 177 
 178     public JavaConstant readFieldValue(ResolvedJavaField field, JavaConstant receiver) {
 179         HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field;
 180         if (hotspotField.isStatic()) {
 181             HotSpotResolvedJavaType holder = (HotSpotResolvedJavaType) hotspotField.getDeclaringClass();
 182             if (holder.isInitialized()) {
 183                 return memoryAccess.readUnsafeConstant(hotspotField.getJavaKind(), HotSpotObjectConstantImpl.forObject(holder.mirror()), hotspotField.offset());
 184             }
 185         } else {
 186             if (receiver.isNonNull() && hotspotField.isInObject(((HotSpotObjectConstantImpl) receiver).object())) {
 187                 return memoryAccess.readUnsafeConstant(hotspotField.getJavaKind(), receiver, hotspotField.offset());
 188             }
 189         }
 190         return null;
 191     }
 192 
 193     @Override
 194     public JavaConstant asJavaClass(ResolvedJavaType type) {
 195         return HotSpotObjectConstantImpl.forObject(((HotSpotResolvedJavaType) type).mirror());
 196     }
 197 
 198     @Override
 199     public Constant asObjectHub(ResolvedJavaType type) {
 200         if (type instanceof HotSpotResolvedObjectType) {
 201             return ((HotSpotResolvedObjectType) type).klass();
 202         } else {
 203             throw JVMCIError.unimplemented();
 204         }
 205     }
 206 }