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 static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset;
  26 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayIndexScale;
  27 import static jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl.fromObjectClass;
  28 import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE;
  29 
  30 import java.lang.reflect.Array;
  31 import java.lang.reflect.Constructor;
  32 import java.lang.reflect.Executable;
  33 import java.lang.reflect.Field;
  34 import java.lang.reflect.Method;
  35 import java.lang.reflect.Modifier;
  36 
  37 import jdk.vm.ci.code.CodeUtil;
  38 import jdk.vm.ci.code.TargetDescription;
  39 import jdk.vm.ci.common.JVMCIError;
  40 import jdk.vm.ci.meta.DeoptimizationAction;
  41 import jdk.vm.ci.meta.DeoptimizationReason;
  42 import jdk.vm.ci.meta.JavaConstant;
  43 import jdk.vm.ci.meta.JavaKind;
  44 import jdk.vm.ci.meta.MetaAccessProvider;
  45 import jdk.vm.ci.meta.ResolvedJavaField;
  46 import jdk.vm.ci.meta.ResolvedJavaMethod;
  47 import jdk.vm.ci.meta.ResolvedJavaType;
  48 import jdk.vm.ci.meta.Signature;
  49 
  50 // JaCoCo Exclude
  51 
  52 /**
  53  * HotSpot implementation of {@link MetaAccessProvider}.
  54  */
  55 public class HotSpotMetaAccessProvider implements MetaAccessProvider, HotSpotProxified {
  56 
  57     protected final HotSpotJVMCIRuntimeProvider runtime;
  58 
  59     public HotSpotMetaAccessProvider(HotSpotJVMCIRuntimeProvider runtime) {
  60         this.runtime = runtime;
  61     }
  62 
  63     public ResolvedJavaType lookupJavaType(Class<?> clazz) {
  64         if (clazz == null) {
  65             throw new IllegalArgumentException("Class parameter was null");
  66         }
  67         return runtime.fromClass(clazz);
  68     }
  69 
  70     public HotSpotResolvedObjectType lookupJavaType(JavaConstant constant) {
  71         if (constant.isNull() || !(constant instanceof HotSpotObjectConstant)) {
  72             return null;
  73         }
  74         return ((HotSpotObjectConstant) constant).getType();
  75     }
  76 
  77     public Signature parseMethodDescriptor(String signature) {
  78         return new HotSpotSignature(runtime, signature);
  79     }
  80 
  81     /**
  82      * {@link Field} object of {@link Method#slot}.
  83      */
  84     private Field reflectionMethodSlot = getReflectionSlotField(Method.class);
  85 
  86     /**
  87      * {@link Field} object of {@link Constructor#slot}.
  88      */
  89     private Field reflectionConstructorSlot = getReflectionSlotField(Constructor.class);
  90 
  91     private static Field getReflectionSlotField(Class<?> reflectionClass) {
  92         try {
  93             Field field = reflectionClass.getDeclaredField("slot");
  94             field.setAccessible(true);
  95             return field;
  96         } catch (NoSuchFieldException | SecurityException e) {
  97             throw new JVMCIError(e);
  98         }
  99     }
 100 
 101     public ResolvedJavaMethod lookupJavaMethod(Executable reflectionMethod) {
 102         try {
 103             Class<?> holder = reflectionMethod.getDeclaringClass();
 104             Field slotField = reflectionMethod instanceof Constructor ? reflectionConstructorSlot : reflectionMethodSlot;
 105             final int slot = slotField.getInt(reflectionMethod);
 106             return runtime.getCompilerToVM().getResolvedJavaMethodAtSlot(holder, slot);
 107         } catch (IllegalArgumentException | IllegalAccessException e) {
 108             throw new JVMCIError(e);
 109         }
 110     }
 111 
 112     public ResolvedJavaField lookupJavaField(Field reflectionField) {
 113         Class<?> fieldHolder = reflectionField.getDeclaringClass();
 114 
 115         HotSpotResolvedObjectType holder = fromObjectClass(fieldHolder);
 116         if (Modifier.isStatic(reflectionField.getModifiers())) {
 117             final long offset = UNSAFE.staticFieldOffset(reflectionField);
 118             for (ResolvedJavaField field : holder.getStaticFields()) {
 119                 if (offset == ((HotSpotResolvedJavaField) field).offset()) {
 120                     return field;
 121                 }
 122             }
 123         } else {
 124             final long offset = UNSAFE.objectFieldOffset(reflectionField);
 125             for (ResolvedJavaField field : holder.getInstanceFields(false)) {
 126                 if (offset == ((HotSpotResolvedJavaField) field).offset()) {
 127                     return field;
 128                 }
 129             }
 130         }
 131 
 132         throw new JVMCIError("unresolved field %s", reflectionField);
 133     }
 134 
 135     private static int intMaskRight(int n) {
 136         assert n <= 32;
 137         return n == 32 ? -1 : (1 << n) - 1;
 138     }
 139 
 140     @Override
 141     public JavaConstant encodeDeoptActionAndReason(DeoptimizationAction action, DeoptimizationReason reason, int debugId) {
 142         HotSpotVMConfig config = runtime.getConfig();
 143         int actionValue = convertDeoptAction(action);
 144         int reasonValue = convertDeoptReason(reason);
 145         int debugValue = debugId & intMaskRight(config.deoptimizationDebugIdBits);
 146         JavaConstant c = JavaConstant.forInt(
 147                         ~((debugValue << config.deoptimizationDebugIdShift) | (reasonValue << config.deoptimizationReasonShift) | (actionValue << config.deoptimizationActionShift)));
 148         assert c.asInt() < 0;
 149         return c;
 150     }
 151 
 152     public DeoptimizationReason decodeDeoptReason(JavaConstant constant) {
 153         HotSpotVMConfig config = runtime.getConfig();
 154         int reasonValue = ((~constant.asInt()) >> config.deoptimizationReasonShift) & intMaskRight(config.deoptimizationReasonBits);
 155         DeoptimizationReason reason = convertDeoptReason(reasonValue);
 156         return reason;
 157     }
 158 
 159     public DeoptimizationAction decodeDeoptAction(JavaConstant constant) {
 160         HotSpotVMConfig config = runtime.getConfig();
 161         int actionValue = ((~constant.asInt()) >> config.deoptimizationActionShift) & intMaskRight(config.deoptimizationActionBits);
 162         DeoptimizationAction action = convertDeoptAction(actionValue);
 163         return action;
 164     }
 165 
 166     public int decodeDebugId(JavaConstant constant) {
 167         HotSpotVMConfig config = runtime.getConfig();
 168         return ((~constant.asInt()) >> config.deoptimizationDebugIdShift) & intMaskRight(config.deoptimizationDebugIdBits);
 169     }
 170 
 171     public int convertDeoptAction(DeoptimizationAction action) {
 172         HotSpotVMConfig config = runtime.getConfig();
 173         switch (action) {
 174             case None:
 175                 return config.deoptActionNone;
 176             case RecompileIfTooManyDeopts:
 177                 return config.deoptActionMaybeRecompile;
 178             case InvalidateReprofile:
 179                 return config.deoptActionReinterpret;
 180             case InvalidateRecompile:
 181                 return config.deoptActionMakeNotEntrant;
 182             case InvalidateStopCompiling:
 183                 return config.deoptActionMakeNotCompilable;
 184             default:
 185                 throw new JVMCIError("%s", action);
 186         }
 187     }
 188 
 189     public DeoptimizationAction convertDeoptAction(int action) {
 190         HotSpotVMConfig config = runtime.getConfig();
 191         if (action == config.deoptActionNone) {
 192             return DeoptimizationAction.None;
 193         }
 194         if (action == config.deoptActionMaybeRecompile) {
 195             return DeoptimizationAction.RecompileIfTooManyDeopts;
 196         }
 197         if (action == config.deoptActionReinterpret) {
 198             return DeoptimizationAction.InvalidateReprofile;
 199         }
 200         if (action == config.deoptActionMakeNotEntrant) {
 201             return DeoptimizationAction.InvalidateRecompile;
 202         }
 203         if (action == config.deoptActionMakeNotCompilable) {
 204             return DeoptimizationAction.InvalidateStopCompiling;
 205         }
 206         throw new JVMCIError("%d", action);
 207     }
 208 
 209     public int convertDeoptReason(DeoptimizationReason reason) {
 210         HotSpotVMConfig config = runtime.getConfig();
 211         switch (reason) {
 212             case None:
 213                 return config.deoptReasonNone;
 214             case NullCheckException:
 215                 return config.deoptReasonNullCheck;
 216             case BoundsCheckException:
 217                 return config.deoptReasonRangeCheck;
 218             case ClassCastException:
 219                 return config.deoptReasonClassCheck;
 220             case ArrayStoreException:
 221                 return config.deoptReasonArrayCheck;
 222             case UnreachedCode:
 223                 return config.deoptReasonUnreached0;
 224             case TypeCheckedInliningViolated:
 225                 return config.deoptReasonTypeCheckInlining;
 226             case OptimizedTypeCheckViolated:
 227                 return config.deoptReasonOptimizedTypeCheck;
 228             case NotCompiledExceptionHandler:
 229                 return config.deoptReasonNotCompiledExceptionHandler;
 230             case Unresolved:
 231                 return config.deoptReasonUnresolved;
 232             case JavaSubroutineMismatch:
 233                 return config.deoptReasonJsrMismatch;
 234             case ArithmeticException:
 235                 return config.deoptReasonDiv0Check;
 236             case RuntimeConstraint:
 237                 return config.deoptReasonConstraint;
 238             case LoopLimitCheck:
 239                 return config.deoptReasonLoopLimitCheck;
 240             case Aliasing:
 241                 return config.deoptReasonAliasing;
 242             case TransferToInterpreter:
 243                 return config.deoptReasonTransferToInterpreter;
 244             default:
 245                 throw new JVMCIError("%s", reason);
 246         }
 247     }
 248 
 249     public DeoptimizationReason convertDeoptReason(int reason) {
 250         HotSpotVMConfig config = runtime.getConfig();
 251         if (reason == config.deoptReasonNone) {
 252             return DeoptimizationReason.None;
 253         }
 254         if (reason == config.deoptReasonNullCheck) {
 255             return DeoptimizationReason.NullCheckException;
 256         }
 257         if (reason == config.deoptReasonRangeCheck) {
 258             return DeoptimizationReason.BoundsCheckException;
 259         }
 260         if (reason == config.deoptReasonClassCheck) {
 261             return DeoptimizationReason.ClassCastException;
 262         }
 263         if (reason == config.deoptReasonArrayCheck) {
 264             return DeoptimizationReason.ArrayStoreException;
 265         }
 266         if (reason == config.deoptReasonUnreached0) {
 267             return DeoptimizationReason.UnreachedCode;
 268         }
 269         if (reason == config.deoptReasonTypeCheckInlining) {
 270             return DeoptimizationReason.TypeCheckedInliningViolated;
 271         }
 272         if (reason == config.deoptReasonOptimizedTypeCheck) {
 273             return DeoptimizationReason.OptimizedTypeCheckViolated;
 274         }
 275         if (reason == config.deoptReasonNotCompiledExceptionHandler) {
 276             return DeoptimizationReason.NotCompiledExceptionHandler;
 277         }
 278         if (reason == config.deoptReasonUnresolved) {
 279             return DeoptimizationReason.Unresolved;
 280         }
 281         if (reason == config.deoptReasonJsrMismatch) {
 282             return DeoptimizationReason.JavaSubroutineMismatch;
 283         }
 284         if (reason == config.deoptReasonDiv0Check) {
 285             return DeoptimizationReason.ArithmeticException;
 286         }
 287         if (reason == config.deoptReasonConstraint) {
 288             return DeoptimizationReason.RuntimeConstraint;
 289         }
 290         if (reason == config.deoptReasonLoopLimitCheck) {
 291             return DeoptimizationReason.LoopLimitCheck;
 292         }
 293         if (reason == config.deoptReasonAliasing) {
 294             return DeoptimizationReason.Aliasing;
 295         }
 296         if (reason == config.deoptReasonTransferToInterpreter) {
 297             return DeoptimizationReason.TransferToInterpreter;
 298         }
 299         throw new JVMCIError("%x", reason);
 300     }
 301 
 302     @Override
 303     public long getMemorySize(JavaConstant constant) {
 304         if (constant.getJavaKind() == JavaKind.Object) {
 305             HotSpotResolvedObjectType lookupJavaType = lookupJavaType(constant);
 306 
 307             if (lookupJavaType == null) {
 308                 return 0;
 309             } else {
 310                 if (lookupJavaType.isArray()) {
 311                     // TODO(tw): Add compressed pointer support.
 312                     int length = Array.getLength(((HotSpotObjectConstantImpl) constant).object());
 313                     ResolvedJavaType elementType = lookupJavaType.getComponentType();
 314                     JavaKind elementKind = elementType.getJavaKind();
 315                     final int headerSize = getArrayBaseOffset(elementKind);
 316                     TargetDescription target = runtime.getHostJVMCIBackend().getTarget();
 317                     int sizeOfElement = getArrayIndexScale(elementKind);
 318                     int alignment = target.wordSize;
 319                     int log2ElementSize = CodeUtil.log2(sizeOfElement);
 320                     return computeArrayAllocationSize(length, alignment, headerSize, log2ElementSize);
 321                 }
 322                 return lookupJavaType.instanceSize();
 323             }
 324         } else {
 325             return constant.getJavaKind().getByteCount();
 326         }
 327     }
 328 
 329     /**
 330      * Computes the size of the memory chunk allocated for an array. This size accounts for the
 331      * array header size, body size and any padding after the last element to satisfy object
 332      * alignment requirements.
 333      *
 334      * @param length the number of elements in the array
 335      * @param alignment the object alignment requirement
 336      * @param headerSize the size of the array header
 337      * @param log2ElementSize log2 of the size of an element in the array
 338      */
 339     public static int computeArrayAllocationSize(int length, int alignment, int headerSize, int log2ElementSize) {
 340         int size = (length << log2ElementSize) + headerSize + (alignment - 1);
 341         int mask = ~(alignment - 1);
 342         return size & mask;
 343     }
 344 }