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