1 /*
   2  * Copyright (c) 2011, 2018, 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.vm.ci.common.JVMCIError;
  29 import jdk.vm.ci.meta.Constant;
  30 import jdk.vm.ci.meta.ConstantReflectionProvider;
  31 import jdk.vm.ci.meta.JavaConstant;
  32 import jdk.vm.ci.meta.JavaKind;
  33 import jdk.vm.ci.meta.MemoryAccessProvider;
  34 import jdk.vm.ci.meta.MethodHandleAccessProvider;
  35 import jdk.vm.ci.meta.ResolvedJavaField;
  36 import jdk.vm.ci.meta.ResolvedJavaType;
  37 
  38 /**
  39  * HotSpot implementation of {@link ConstantReflectionProvider}.
  40  */
  41 public class HotSpotConstantReflectionProvider implements ConstantReflectionProvider {
  42 
  43     protected final HotSpotJVMCIRuntime runtime;
  44     protected final HotSpotMethodHandleAccessProvider methodHandleAccess;
  45     private final HotSpotMemoryAccessProviderImpl memoryAccess;
  46 
  47     public HotSpotConstantReflectionProvider(HotSpotJVMCIRuntime runtime) {
  48         this.runtime = runtime;
  49         this.methodHandleAccess = new HotSpotMethodHandleAccessProvider(this);
  50         this.memoryAccess = new HotSpotMemoryAccessProviderImpl(runtime);
  51     }
  52 
  53     @Override
  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      * @return true if the box is cached
 112      */
 113     private static boolean isBoxCached(JavaConstant source) {
 114         switch (source.getJavaKind()) {
 115             case Boolean:
 116                 return true;
 117             case Char:
 118                 return source.asInt() <= 127;
 119             case Byte:
 120             case Short:
 121             case Int:
 122                 return source.asInt() >= -128 && source.asInt() <= 127;
 123             case Long:
 124                 return source.asLong() >= -128 && source.asLong() <= 127;
 125             case Float:
 126             case Double:
 127                 return false;
 128             default:
 129                 throw new IllegalArgumentException("unexpected kind " + source.getJavaKind());
 130         }
 131     }
 132 
 133     @Override
 134     public JavaConstant boxPrimitive(JavaConstant source) {
 135         if (source == null || !source.getJavaKind().isPrimitive() || !isBoxCached(source)) {
 136             return null;
 137         }
 138         return HotSpotObjectConstantImpl.forObject(source.asBoxedPrimitive());
 139     }
 140 
 141     @Override
 142     public JavaConstant unboxPrimitive(JavaConstant source) {
 143         if (source == null || !source.getJavaKind().isObject()) {
 144             return null;
 145         }
 146         if (source.isNull()) {
 147             return null;
 148         }
 149         return JavaConstant.forBoxedPrimitive(((HotSpotObjectConstantImpl) source).object());
 150     }
 151 
 152     @Override
 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     @Override
 179     public JavaConstant readFieldValue(ResolvedJavaField field, JavaConstant receiver) {
 180         HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field;
 181         if (hotspotField.isStatic()) {
 182             HotSpotResolvedJavaType holder = (HotSpotResolvedJavaType) hotspotField.getDeclaringClass();
 183             if (holder.isInitialized()) {
 184                 return memoryAccess.readFieldValue(hotspotField, holder.mirror(), field.isVolatile());
 185             }
 186         } else {
 187             if (receiver.isNonNull()) {
 188                 Object object = ((HotSpotObjectConstantImpl) receiver).object();
 189                 if (hotspotField.isInObject(receiver)) {
 190                     return memoryAccess.readFieldValue(hotspotField, object, field.isVolatile());
 191                 }
 192             }
 193         }
 194         return null;
 195     }
 196 
 197     @Override
 198     public JavaConstant asJavaClass(ResolvedJavaType type) {
 199         return HotSpotObjectConstantImpl.forObject(((HotSpotResolvedJavaType) type).mirror());
 200     }
 201 
 202     @Override
 203     public Constant asObjectHub(ResolvedJavaType type) {
 204         if (type instanceof HotSpotResolvedObjectType) {
 205             return ((HotSpotResolvedObjectType) type).klass();
 206         } else {
 207             throw JVMCIError.unimplemented();
 208         }
 209     }
 210 }