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 }