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