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 }