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 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(~((debugValue << config.deoptimizationDebugIdShift) | (reasonValue << config.deoptimizationReasonShift) | (actionValue << config.deoptimizationActionShift)));
 147         assert c.asInt() < 0;
 148         return c;
 149     }
 150 
 151     public DeoptimizationReason decodeDeoptReason(JavaConstant constant) {
 152         HotSpotVMConfig config = runtime.getConfig();
 153         int reasonValue = ((~constant.asInt()) >> config.deoptimizationReasonShift) & intMaskRight(config.deoptimizationReasonBits);
 154         DeoptimizationReason reason = convertDeoptReason(reasonValue);
 155         return reason;
 156     }
 157 
 158     public DeoptimizationAction decodeDeoptAction(JavaConstant constant) {
 159         HotSpotVMConfig config = runtime.getConfig();
 160         int actionValue = ((~constant.asInt()) >> config.deoptimizationActionShift) & intMaskRight(config.deoptimizationActionBits);
 161         DeoptimizationAction action = convertDeoptAction(actionValue);
 162         return action;
 163     }
 164 
 165     public int decodeDebugId(JavaConstant constant) {
 166         HotSpotVMConfig config = runtime.getConfig();
 167         return ((~constant.asInt()) >> config.deoptimizationDebugIdShift) & intMaskRight(config.deoptimizationDebugIdBits);
 168     }
 169 
 170     public int convertDeoptAction(DeoptimizationAction action) {
 171         HotSpotVMConfig config = runtime.getConfig();
 172         switch (action) {
 173             case None:
 174                 return config.deoptActionNone;
 175             case RecompileIfTooManyDeopts:
 176                 return config.deoptActionMaybeRecompile;
 177             case InvalidateReprofile:
 178                 return config.deoptActionReinterpret;
 179             case InvalidateRecompile:
 180                 return config.deoptActionMakeNotEntrant;
 181             case InvalidateStopCompiling:
 182                 return config.deoptActionMakeNotCompilable;
 183             default:
 184                 throw new JVMCIError("%s", action);
 185         }
 186     }
 187 
 188     public DeoptimizationAction convertDeoptAction(int action) {
 189         HotSpotVMConfig config = runtime.getConfig();
 190         if (action == config.deoptActionNone) {
 191             return DeoptimizationAction.None;
 192         }
 193         if (action == config.deoptActionMaybeRecompile) {
 194             return DeoptimizationAction.RecompileIfTooManyDeopts;
 195         }
 196         if (action == config.deoptActionReinterpret) {
 197             return DeoptimizationAction.InvalidateReprofile;
 198         }
 199         if (action == config.deoptActionMakeNotEntrant) {
 200             return DeoptimizationAction.InvalidateRecompile;
 201         }
 202         if (action == config.deoptActionMakeNotCompilable) {
 203             return DeoptimizationAction.InvalidateStopCompiling;
 204         }
 205         throw new JVMCIError("%d", action);
 206     }
 207 
 208     public int convertDeoptReason(DeoptimizationReason reason) {
 209         HotSpotVMConfig config = runtime.getConfig();
 210         switch (reason) {
 211             case None:
 212                 return config.deoptReasonNone;
 213             case NullCheckException:
 214                 return config.deoptReasonNullCheck;
 215             case BoundsCheckException:
 216                 return config.deoptReasonRangeCheck;
 217             case ClassCastException:
 218                 return config.deoptReasonClassCheck;
 219             case ArrayStoreException:
 220                 return config.deoptReasonArrayCheck;
 221             case UnreachedCode:
 222                 return config.deoptReasonUnreached0;
 223             case TypeCheckedInliningViolated:
 224                 return config.deoptReasonTypeCheckInlining;
 225             case OptimizedTypeCheckViolated:
 226                 return config.deoptReasonOptimizedTypeCheck;
 227             case NotCompiledExceptionHandler:
 228                 return config.deoptReasonNotCompiledExceptionHandler;
 229             case Unresolved:
 230                 return config.deoptReasonUnresolved;
 231             case JavaSubroutineMismatch:
 232                 return config.deoptReasonJsrMismatch;
 233             case ArithmeticException:
 234                 return config.deoptReasonDiv0Check;
 235             case RuntimeConstraint:
 236                 return config.deoptReasonConstraint;
 237             case LoopLimitCheck:
 238                 return config.deoptReasonLoopLimitCheck;
 239             case Aliasing:
 240                 return config.deoptReasonAliasing;
 241             case TransferToInterpreter:
 242                 return config.deoptReasonTransferToInterpreter;
 243             default:
 244                 throw new JVMCIError("%s", reason);
 245         }
 246     }
 247 
 248     public DeoptimizationReason convertDeoptReason(int reason) {
 249         HotSpotVMConfig config = runtime.getConfig();
 250         if (reason == config.deoptReasonNone) {
 251             return DeoptimizationReason.None;
 252         }
 253         if (reason == config.deoptReasonNullCheck) {
 254             return DeoptimizationReason.NullCheckException;
 255         }
 256         if (reason == config.deoptReasonRangeCheck) {
 257             return DeoptimizationReason.BoundsCheckException;
 258         }
 259         if (reason == config.deoptReasonClassCheck) {
 260             return DeoptimizationReason.ClassCastException;
 261         }
 262         if (reason == config.deoptReasonArrayCheck) {
 263             return DeoptimizationReason.ArrayStoreException;
 264         }
 265         if (reason == config.deoptReasonUnreached0) {
 266             return DeoptimizationReason.UnreachedCode;
 267         }
 268         if (reason == config.deoptReasonTypeCheckInlining) {
 269             return DeoptimizationReason.TypeCheckedInliningViolated;
 270         }
 271         if (reason == config.deoptReasonOptimizedTypeCheck) {
 272             return DeoptimizationReason.OptimizedTypeCheckViolated;
 273         }
 274         if (reason == config.deoptReasonNotCompiledExceptionHandler) {
 275             return DeoptimizationReason.NotCompiledExceptionHandler;
 276         }
 277         if (reason == config.deoptReasonUnresolved) {
 278             return DeoptimizationReason.Unresolved;
 279         }
 280         if (reason == config.deoptReasonJsrMismatch) {
 281             return DeoptimizationReason.JavaSubroutineMismatch;
 282         }
 283         if (reason == config.deoptReasonDiv0Check) {
 284             return DeoptimizationReason.ArithmeticException;
 285         }
 286         if (reason == config.deoptReasonConstraint) {
 287             return DeoptimizationReason.RuntimeConstraint;
 288         }
 289         if (reason == config.deoptReasonLoopLimitCheck) {
 290             return DeoptimizationReason.LoopLimitCheck;
 291         }
 292         if (reason == config.deoptReasonAliasing) {
 293             return DeoptimizationReason.Aliasing;
 294         }
 295         if (reason == config.deoptReasonTransferToInterpreter) {
 296             return DeoptimizationReason.TransferToInterpreter;
 297         }
 298         throw new JVMCIError("%x", reason);
 299     }
 300 
 301     @Override
 302     public long getMemorySize(JavaConstant constant) {
 303         if (constant.getJavaKind() == JavaKind.Object) {
 304             HotSpotResolvedObjectType lookupJavaType = lookupJavaType(constant);
 305 
 306             if (lookupJavaType == null) {
 307                 return 0;
 308             } else {
 309                 if (lookupJavaType.isArray()) {
 310                     // TODO(tw): Add compressed pointer support.
 311                     int length = Array.getLength(((HotSpotObjectConstantImpl) constant).object());
 312                     ResolvedJavaType elementType = lookupJavaType.getComponentType();
 313                     JavaKind elementKind = elementType.getJavaKind();
 314                     final int headerSize = getArrayBaseOffset(elementKind);
 315                     TargetDescription target = runtime.getHostJVMCIBackend().getTarget();
 316                     int sizeOfElement = getArrayIndexScale(elementKind);
 317                     int alignment = target.wordSize;
 318                     int log2ElementSize = CodeUtil.log2(sizeOfElement);
 319                     return computeArrayAllocationSize(length, alignment, headerSize, log2ElementSize);
 320                 }
 321                 return lookupJavaType.instanceSize();
 322             }
 323         } else {
 324             return constant.getJavaKind().getByteCount();
 325         }
 326     }
 327 
 328     /**
 329      * Computes the size of the memory chunk allocated for an array. This size accounts for the
 330      * array header size, body size and any padding after the last element to satisfy object
 331      * alignment requirements.
 332      *
 333      * @param length the number of elements in the array
 334      * @param alignment the object alignment requirement
 335      * @param headerSize the size of the array header
 336      * @param log2ElementSize log2 of the size of an element in the array
 337      */
 338     public static int computeArrayAllocationSize(int length, int alignment, int headerSize, int log2ElementSize) {
 339         int size = (length << log2ElementSize) + headerSize + (alignment - 1);
 340         int mask = ~(alignment - 1);
 341         return size & mask;
 342     }
 343 }