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