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 }