1 /* 2 * Copyright (c) 2011, 2019, 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.CompilerToVM.compilerToVM; 26 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; 27 import static jdk.vm.ci.hotspot.HotSpotVMConfig.config; 28 import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; 29 30 import jdk.vm.ci.common.JVMCIError; 31 import jdk.vm.ci.common.NativeImageReinitialize; 32 import jdk.vm.ci.meta.ConstantPool; 33 import jdk.vm.ci.meta.JavaConstant; 34 import jdk.vm.ci.meta.JavaField; 35 import jdk.vm.ci.meta.JavaMethod; 36 import jdk.vm.ci.meta.JavaType; 37 import jdk.vm.ci.meta.ResolvedJavaMethod; 38 import jdk.vm.ci.meta.ResolvedJavaType; 39 import jdk.vm.ci.meta.Signature; 40 import jdk.vm.ci.meta.UnresolvedJavaField; 41 import jdk.vm.ci.meta.UnresolvedJavaMethod; 42 import jdk.vm.ci.meta.UnresolvedJavaType; 43 44 /** 45 * Implementation of {@link ConstantPool} for HotSpot. 46 */ 47 public final class HotSpotConstantPool implements ConstantPool, MetaspaceHandleObject { 48 49 /** 50 * Subset of JVM bytecode opcodes used by {@link HotSpotConstantPool}. 51 */ 52 public static class Bytecodes { 53 public static final int LDC = 18; // 0x12 54 public static final int LDC_W = 19; // 0x13 55 public static final int LDC2_W = 20; // 0x14 56 public static final int GETSTATIC = 178; // 0xB2 57 public static final int PUTSTATIC = 179; // 0xB3 58 public static final int GETFIELD = 180; // 0xB4 59 public static final int PUTFIELD = 181; // 0xB5 60 public static final int INVOKEVIRTUAL = 182; // 0xB6 61 public static final int INVOKESPECIAL = 183; // 0xB7 62 public static final int INVOKESTATIC = 184; // 0xB8 63 public static final int INVOKEINTERFACE = 185; // 0xB9 64 public static final int INVOKEDYNAMIC = 186; // 0xBA 65 public static final int NEW = 187; // 0xBB 66 public static final int NEWARRAY = 188; // 0xBC 67 public static final int ANEWARRAY = 189; // 0xBD 68 public static final int CHECKCAST = 192; // 0xC0 69 public static final int INSTANCEOF = 193; // 0xC1 70 public static final int MULTIANEWARRAY = 197; // 0xC5 71 isInvoke(int opcode)72 static boolean isInvoke(int opcode) { 73 switch (opcode) { 74 case INVOKEVIRTUAL: 75 case INVOKESPECIAL: 76 case INVOKESTATIC: 77 case INVOKEINTERFACE: 78 case INVOKEDYNAMIC: 79 return true; 80 default: 81 return false; 82 } 83 } 84 85 /** 86 * See: {@code Rewriter::maybe_rewrite_invokehandle}. 87 */ isInvokeHandleAlias(int opcode)88 static boolean isInvokeHandleAlias(int opcode) { 89 switch (opcode) { 90 case INVOKEVIRTUAL: 91 case INVOKESPECIAL: 92 return true; 93 default: 94 return false; 95 } 96 } 97 } 98 99 static final class JvmConstant { 100 private final int tag; 101 private final String name; 102 JvmConstant(int tag, String name)103 JvmConstant(int tag, String name) { 104 this.tag = tag; 105 this.name = name; 106 } 107 108 @Override toString()109 public String toString() { 110 return name; 111 } 112 } 113 114 /** 115 * {@code JVM_CONSTANT} constants used in the VM including both public and internal ones. 116 */ 117 static final class JvmConstants { 118 119 private final HotSpotVMConfig c = config(); 120 private final int externalMax = c.jvmConstantExternalMax; 121 private final int internalMax = c.jvmConstantInternalMax; 122 private final int internalMin = c.jvmConstantInternalMin; 123 private final JvmConstant[] table = new JvmConstant[externalMax + 1 + (internalMax - internalMin) + 1]; 124 125 final JvmConstant jvmUtf8 = add(new JvmConstant(c.jvmConstantUtf8, "Utf8")); 126 final JvmConstant jvmInteger = add(new JvmConstant(c.jvmConstantInteger, "Integer")); 127 final JvmConstant jvmLong = add(new JvmConstant(c.jvmConstantLong, "Long")); 128 final JvmConstant jvmFloat = add(new JvmConstant(c.jvmConstantFloat, "Float")); 129 final JvmConstant jvmDouble = add(new JvmConstant(c.jvmConstantDouble, "Double")); 130 final JvmConstant jvmClass = add(new JvmConstant(c.jvmConstantClass, "Class")); 131 final JvmConstant jvmUnresolvedClass = add(new JvmConstant(c.jvmConstantUnresolvedClass, "UnresolvedClass")); 132 final JvmConstant jvmUnresolvedClassInError = add(new JvmConstant(c.jvmConstantUnresolvedClassInError, "UnresolvedClassInError")); 133 final JvmConstant jvmString = add(new JvmConstant(c.jvmConstantString, "String")); 134 final JvmConstant jvmFieldref = add(new JvmConstant(c.jvmConstantFieldref, "Fieldref")); 135 final JvmConstant jvmMethodref = add(new JvmConstant(c.jvmConstantMethodref, "Methodref")); 136 final JvmConstant jvmInterfaceMethodref = add(new JvmConstant(c.jvmConstantInterfaceMethodref, "InterfaceMethodref")); 137 final JvmConstant jvmNameAndType = add(new JvmConstant(c.jvmConstantNameAndType, "NameAndType")); 138 final JvmConstant jvmMethodHandle = add(new JvmConstant(c.jvmConstantMethodHandle, "MethodHandle")); 139 final JvmConstant jvmMethodHandleInError = add(new JvmConstant(c.jvmConstantMethodHandleInError, "MethodHandleInError")); 140 final JvmConstant jvmMethodType = add(new JvmConstant(c.jvmConstantMethodType, "MethodType")); 141 final JvmConstant jvmMethodTypeInError = add(new JvmConstant(c.jvmConstantMethodTypeInError, "MethodTypeInError")); 142 final JvmConstant jvmInvokeDynamic = add(new JvmConstant(c.jvmConstantInvokeDynamic, "InvokeDynamic")); 143 add(JvmConstant constant)144 private JvmConstant add(JvmConstant constant) { 145 table[indexOf(constant.tag)] = constant; 146 return constant; 147 } 148 indexOf(int tag)149 private int indexOf(int tag) { 150 if (tag >= internalMin) { 151 return tag - internalMin + externalMax + 1; 152 } else { 153 assert tag <= externalMax; 154 } 155 return tag; 156 } 157 get(int tag)158 JvmConstant get(int tag) { 159 JvmConstant res = table[indexOf(tag)]; 160 if (res != null) { 161 return res; 162 } 163 throw new JVMCIError("Unknown JvmConstant tag %s", tag); 164 } 165 166 @NativeImageReinitialize private static volatile JvmConstants instance; 167 instance()168 static JvmConstants instance() { 169 JvmConstants result = instance; 170 if (result == null) { 171 synchronized (JvmConstants.class) { 172 result = instance; 173 if (result == null) { 174 instance = result = new JvmConstants(); 175 } 176 } 177 } 178 return result; 179 } 180 } 181 182 private static class LookupTypeCacheElement { 183 int lastCpi = Integer.MIN_VALUE; 184 JavaType javaType; 185 LookupTypeCacheElement(int lastCpi, JavaType javaType)186 LookupTypeCacheElement(int lastCpi, JavaType javaType) { 187 super(); 188 this.lastCpi = lastCpi; 189 this.javaType = javaType; 190 } 191 } 192 193 /** 194 * Handle to the {@code ConstantPool} VM object. The handle is in 195 * {@code JVMCI::_metadata_handles}. 196 */ 197 private final long metadataHandle; 198 199 private volatile LookupTypeCacheElement lastLookupType; 200 private final JvmConstants constants; 201 202 /** 203 * Gets the JVMCI mirror from a HotSpot constant pool.The VM is responsible for ensuring that 204 * the ConstantPool is kept alive for the duration of this call and the 205 * {@link HotSpotJVMCIRuntime} keeps it alive after that. 206 * 207 * Called from the VM. 208 * 209 * @param metaspaceConstantPool a metaspace ConstantPool object 210 * @return the {@link HotSpotConstantPool} corresponding to {@code metaspaceConstantPool} 211 */ 212 @SuppressWarnings("unused") 213 @VMEntryPoint fromMetaspace(long metaspaceConstantPool)214 private static HotSpotConstantPool fromMetaspace(long metaspaceConstantPool) { 215 return new HotSpotConstantPool(metaspaceConstantPool); 216 } 217 HotSpotConstantPool(long metadataHandle)218 private HotSpotConstantPool(long metadataHandle) { 219 this.metadataHandle = metadataHandle; 220 this.constants = JvmConstants.instance(); 221 HandleCleaner.create(this, metadataHandle); 222 } 223 224 /** 225 * Gets the holder for this constant pool as {@link HotSpotResolvedObjectTypeImpl}. 226 * 227 * @return holder for this constant pool 228 */ getHolder()229 private HotSpotResolvedObjectType getHolder() { 230 return compilerToVM().getResolvedJavaType(this, config().constantPoolHolderOffset, false); 231 } 232 233 /** 234 * Converts a raw index from the bytecodes to a constant pool cache index by adding a 235 * {@link HotSpotVMConfig#constantPoolCpCacheIndexTag constant}. 236 * 237 * @param rawIndex index from the bytecode 238 * @param opcode bytecode to convert the index for 239 * @return constant pool cache index 240 */ rawIndexToConstantPoolCacheIndex(int rawIndex, int opcode)241 private static int rawIndexToConstantPoolCacheIndex(int rawIndex, int opcode) { 242 int index; 243 if (opcode == Bytecodes.INVOKEDYNAMIC) { 244 index = rawIndex; 245 // See: ConstantPool::is_invokedynamic_index 246 assert index < 0 : "not an invokedynamic constant pool index " + index; 247 } else { 248 assert opcode == Bytecodes.GETFIELD || opcode == Bytecodes.PUTFIELD || opcode == Bytecodes.GETSTATIC || opcode == Bytecodes.PUTSTATIC || opcode == Bytecodes.INVOKEINTERFACE || 249 opcode == Bytecodes.INVOKEVIRTUAL || opcode == Bytecodes.INVOKESPECIAL || opcode == Bytecodes.INVOKESTATIC : "unexpected invoke opcode " + opcode; 250 index = rawIndex + config().constantPoolCpCacheIndexTag; 251 } 252 return index; 253 } 254 255 /** 256 * Decode a constant pool cache index to a constant pool index. 257 * 258 * See {@code ConstantPool::decode_cpcache_index}. 259 * 260 * @param index constant pool cache index 261 * @return decoded index 262 */ 263 private static int decodeConstantPoolCacheIndex(int index) { 264 if (isInvokedynamicIndex(index)) { 265 return decodeInvokedynamicIndex(index); 266 } else { 267 return index - config().constantPoolCpCacheIndexTag; 268 } 269 } 270 271 /** 272 * See {@code ConstantPool::is_invokedynamic_index}. 273 */ 274 private static boolean isInvokedynamicIndex(int index) { 275 return index < 0; 276 } 277 278 /** 279 * See {@code ConstantPool::decode_invokedynamic_index}. 280 */ 281 private static int decodeInvokedynamicIndex(int i) { 282 assert isInvokedynamicIndex(i) : i; 283 return ~i; 284 } 285 286 long getMetaspaceConstantPool() { 287 return getMetaspacePointer(); 288 } 289 290 @Override 291 public long getMetadataHandle() { 292 return metadataHandle; 293 } 294 295 /** 296 * Gets the constant pool tag at index {@code index}. 297 * 298 * @param index constant pool index 299 * @return constant pool tag 300 */ 301 private JvmConstant getTagAt(int index) { 302 assert checkBounds(index); 303 HotSpotVMConfig config = config(); 304 final long metaspaceConstantPoolTags = UNSAFE.getAddress(getMetaspaceConstantPool() + config.constantPoolTagsOffset); 305 final int tag = UNSAFE.getByteVolatile(null, metaspaceConstantPoolTags + config.arrayU1DataOffset + index); 306 if (tag == 0) { 307 return null; 308 } 309 return constants.get(tag); 310 } 311 312 /** 313 * Gets the constant pool entry at index {@code index}. 314 * 315 * @param index constant pool index 316 * @return constant pool entry 317 */ 318 long getEntryAt(int index) { 319 assert checkBounds(index); 320 int offset = index * runtime().getHostJVMCIBackend().getTarget().wordSize; 321 return UNSAFE.getAddress(getMetaspaceConstantPool() + config().constantPoolSize + offset); 322 } 323 324 /** 325 * Gets the integer constant pool entry at index {@code index}. 326 * 327 * @param index constant pool index 328 * @return integer constant pool entry at index 329 */ 330 private int getIntAt(int index) { 331 assert checkTag(index, constants.jvmInteger); 332 int offset = index * runtime().getHostJVMCIBackend().getTarget().wordSize; 333 return UNSAFE.getInt(getMetaspaceConstantPool() + config().constantPoolSize + offset); 334 } 335 336 /** 337 * Gets the long constant pool entry at index {@code index}. 338 * 339 * @param index constant pool index 340 * @return long constant pool entry 341 */ 342 private long getLongAt(int index) { 343 assert checkTag(index, constants.jvmLong); 344 int offset = index * runtime().getHostJVMCIBackend().getTarget().wordSize; 345 return UNSAFE.getLong(getMetaspaceConstantPool() + config().constantPoolSize + offset); 346 } 347 348 /** 349 * Gets the float constant pool entry at index {@code index}. 350 * 351 * @param index constant pool index 352 * @return float constant pool entry 353 */ 354 private float getFloatAt(int index) { 355 assert checkTag(index, constants.jvmFloat); 356 int offset = index * runtime().getHostJVMCIBackend().getTarget().wordSize; 357 return UNSAFE.getFloat(getMetaspaceConstantPool() + config().constantPoolSize + offset); 358 } 359 360 /** 361 * Gets the double constant pool entry at index {@code index}. 362 * 363 * @param index constant pool index 364 * @return float constant pool entry 365 */ 366 private double getDoubleAt(int index) { 367 assert checkTag(index, constants.jvmDouble); 368 int offset = index * runtime().getHostJVMCIBackend().getTarget().wordSize; 369 return UNSAFE.getDouble(getMetaspaceConstantPool() + config().constantPoolSize + offset); 370 } 371 372 /** 373 * Gets the {@code JVM_CONSTANT_NameAndType} constant pool entry at index {@code index}. 374 * 375 * @param index constant pool index 376 * @return {@code JVM_CONSTANT_NameAndType} constant pool entry 377 */ 378 private int getNameAndTypeAt(int index) { 379 assert checkTag(index, constants.jvmNameAndType); 380 int offset = index * runtime().getHostJVMCIBackend().getTarget().wordSize; 381 return UNSAFE.getInt(getMetaspaceConstantPool() + config().constantPoolSize + offset); 382 } 383 384 /** 385 * Gets the {@code JVM_CONSTANT_NameAndType} reference index constant pool entry at index 386 * {@code index}. 387 * 388 * @param index constant pool index 389 * @return {@code JVM_CONSTANT_NameAndType} reference constant pool entry 390 */ 391 private int getNameAndTypeRefIndexAt(int index) { 392 return compilerToVM().lookupNameAndTypeRefIndexInPool(this, index); 393 } 394 395 /** 396 * Gets the name of a {@code JVM_CONSTANT_NameAndType} constant pool entry referenced by another 397 * entry denoted by {@code which}. 398 * 399 * @param which constant pool index or constant pool cache index 400 * @return name as {@link String} 401 */ 402 private String getNameOf(int which) { 403 return compilerToVM().lookupNameInPool(this, which); 404 } 405 406 /** 407 * Gets the name reference index of a {@code JVM_CONSTANT_NameAndType} constant pool entry at 408 * index {@code index}. 409 * 410 * @param index constant pool index 411 * @return name reference index 412 */ 413 private int getNameRefIndexAt(int index) { 414 final int refIndex = getNameAndTypeAt(index); 415 // name ref index is in the low 16-bits. 416 return refIndex & 0xFFFF; 417 } 418 419 /** 420 * Gets the signature of a {@code JVM_CONSTANT_NameAndType} constant pool entry referenced by 421 * another entry denoted by {@code which}. 422 * 423 * @param which constant pool index or constant pool cache index 424 * @return signature as {@link String} 425 */ 426 private String getSignatureOf(int which) { 427 return compilerToVM().lookupSignatureInPool(this, which); 428 } 429 430 /** 431 * Gets the signature reference index of a {@code JVM_CONSTANT_NameAndType} constant pool entry 432 * at index {@code index}. 433 * 434 * @param index constant pool index 435 * @return signature reference index 436 */ 437 private int getSignatureRefIndexAt(int index) { 438 final int refIndex = getNameAndTypeAt(index); 439 // signature ref index is in the high 16-bits. 440 return refIndex >>> 16; 441 } 442 443 /** 444 * Gets the klass reference index constant pool entry at index {@code index}. 445 * 446 * @param index constant pool index 447 * @return klass reference index 448 */ getKlassRefIndexAt(int index)449 private int getKlassRefIndexAt(int index) { 450 return compilerToVM().lookupKlassRefIndexInPool(this, index); 451 } 452 453 /** 454 * Gets the uncached klass reference index constant pool entry at index {@code index}. See: 455 * {@code ConstantPool::uncached_klass_ref_index_at}. 456 * 457 * @param index constant pool index 458 * @return klass reference index 459 */ getUncachedKlassRefIndexAt(int index)460 private int getUncachedKlassRefIndexAt(int index) { 461 assert checkTagIsFieldOrMethod(index); 462 int offset = index * runtime().getHostJVMCIBackend().getTarget().wordSize; 463 final int refIndex = UNSAFE.getInt(getMetaspaceConstantPool() + config().constantPoolSize + offset); 464 // klass ref index is in the low 16-bits. 465 return refIndex & 0xFFFF; 466 } 467 468 /** 469 * Checks that the constant pool index {@code index} is in the bounds of the constant pool. 470 * 471 * @param index constant pool index 472 * @throws AssertionError if the check fails 473 */ checkBounds(int index)474 private boolean checkBounds(int index) { 475 assert 0 <= index && index < length() : "index " + index + " not between 0 and " + length(); 476 return true; 477 } 478 479 /** 480 * Checks that the constant pool tag at index {@code index} is equal to {@code tag}. 481 * 482 * @param index constant pool index 483 * @param tag expected tag 484 * @throws AssertionError if the check fails 485 */ 486 private boolean checkTag(int index, JvmConstant tag) { 487 final JvmConstant tagAt = getTagAt(index); 488 assert tagAt == tag : "constant pool tag at index " + index + " is " + tagAt + " but expected " + tag; 489 return true; 490 } 491 492 /** 493 * Asserts that the constant pool tag at index {@code index} is a 494 * {@link JvmConstants#jvmFieldref}, or a {@link JvmConstants#jvmMethodref}, or a 495 * {@link JvmConstants#jvmInterfaceMethodref}. 496 * 497 * @param index constant pool index 498 * @throws AssertionError if the check fails 499 */ 500 private boolean checkTagIsFieldOrMethod(int index) { 501 final JvmConstant tagAt = getTagAt(index); 502 assert tagAt == constants.jvmFieldref || tagAt == constants.jvmMethodref || tagAt == constants.jvmInterfaceMethodref : tagAt; 503 return true; 504 } 505 506 @Override 507 public int length() { 508 return UNSAFE.getInt(getMetaspaceConstantPool() + config().constantPoolLengthOffset); 509 } 510 511 public boolean hasDynamicConstant() { 512 return (flags() & config().constantPoolHasDynamicConstant) != 0; 513 } 514 515 private int flags() { 516 return UNSAFE.getInt(getMetaspaceConstantPool() + config().constantPoolFlagsOffset); 517 } 518 519 @Override 520 public Object lookupConstant(int cpi) { 521 assert cpi != 0; 522 final JvmConstant tag = getTagAt(cpi); 523 switch (tag.name) { 524 case "Integer": 525 return JavaConstant.forInt(getIntAt(cpi)); 526 case "Long": 527 return JavaConstant.forLong(getLongAt(cpi)); 528 case "Float": 529 return JavaConstant.forFloat(getFloatAt(cpi)); 530 case "Double": 531 return JavaConstant.forDouble(getDoubleAt(cpi)); 532 case "Class": 533 case "UnresolvedClass": 534 case "UnresolvedClassInError": 535 final int opcode = -1; // opcode is not used 536 return lookupType(cpi, opcode); 537 case "String": 538 /* 539 * Normally, we would expect a String here, but unsafe anonymous classes can have 540 * "pseudo strings" (arbitrary live objects) patched into a String entry. Such 541 * entries do not have a symbol in the constant pool slot. 542 */ 543 return compilerToVM().resolvePossiblyCachedConstantInPool(this, cpi); 544 case "MethodHandle": 545 case "MethodHandleInError": 546 case "MethodType": 547 case "MethodTypeInError": 548 return compilerToVM().resolvePossiblyCachedConstantInPool(this, cpi); 549 default: 550 throw new JVMCIError("Unknown constant pool tag %s", tag); 551 } 552 } 553 554 @Override 555 public String lookupUtf8(int cpi) { 556 assert checkTag(cpi, constants.jvmUtf8); 557 return compilerToVM().getSymbol(getEntryAt(cpi)); 558 } 559 560 @Override 561 public Signature lookupSignature(int cpi) { 562 return new HotSpotSignature(runtime(), lookupUtf8(cpi)); 563 } 564 565 @Override 566 public JavaConstant lookupAppendix(int cpi, int opcode) { 567 assert Bytecodes.isInvoke(opcode); 568 final int index = rawIndexToConstantPoolCacheIndex(cpi, opcode); 569 return compilerToVM().lookupAppendixInPool(this, index); 570 } 571 572 /** 573 * Gets a {@link JavaType} corresponding a given resolved or unresolved type. 574 * 575 * @param type either a ResolvedJavaType or a String naming a unresolved type. 576 */ 577 private static JavaType getJavaType(final Object type) { 578 if (type instanceof String) { 579 String name = (String) type; 580 return UnresolvedJavaType.create("L" + name + ";"); 581 } else { 582 return (JavaType) type; 583 } 584 } 585 586 @Override 587 public JavaMethod lookupMethod(int cpi, int opcode) { 588 final int index = rawIndexToConstantPoolCacheIndex(cpi, opcode); 589 final HotSpotResolvedJavaMethod method = compilerToVM().lookupMethodInPool(this, index, (byte) opcode); 590 if (method != null) { 591 return method; 592 } else { 593 // Get the method's name and signature. 594 String name = getNameOf(index); 595 HotSpotSignature signature = new HotSpotSignature(runtime(), getSignatureOf(index)); 596 if (opcode == Bytecodes.INVOKEDYNAMIC) { 597 HotSpotResolvedObjectType holder = runtime().getMethodHandleClass(); 598 return new UnresolvedJavaMethod(name, signature, holder); 599 } else { 600 final int klassIndex = getKlassRefIndexAt(index); 601 final Object type = compilerToVM().lookupKlassInPool(this, klassIndex); 602 JavaType holder = getJavaType(type); 603 return new UnresolvedJavaMethod(name, signature, holder); 604 } 605 } 606 } 607 608 @Override 609 public JavaType lookupType(int cpi, int opcode) { 610 final LookupTypeCacheElement elem = this.lastLookupType; 611 if (elem != null && elem.lastCpi == cpi) { 612 return elem.javaType; 613 } else { 614 final Object type = compilerToVM().lookupKlassInPool(this, cpi); 615 JavaType result = getJavaType(type); 616 if (result instanceof ResolvedJavaType) { 617 this.lastLookupType = new LookupTypeCacheElement(cpi, result); 618 } 619 return result; 620 } 621 } 622 623 @Override 624 public JavaType lookupReferencedType(int cpi, int opcode) { 625 int index; 626 switch (opcode) { 627 case Bytecodes.CHECKCAST: 628 case Bytecodes.INSTANCEOF: 629 case Bytecodes.NEW: 630 case Bytecodes.ANEWARRAY: 631 case Bytecodes.MULTIANEWARRAY: 632 case Bytecodes.LDC: 633 case Bytecodes.LDC_W: 634 case Bytecodes.LDC2_W: 635 index = cpi; 636 break; 637 case Bytecodes.GETSTATIC: 638 case Bytecodes.PUTSTATIC: 639 case Bytecodes.GETFIELD: 640 case Bytecodes.PUTFIELD: 641 case Bytecodes.INVOKEVIRTUAL: 642 case Bytecodes.INVOKESPECIAL: 643 case Bytecodes.INVOKESTATIC: 644 case Bytecodes.INVOKEINTERFACE: { 645 index = rawIndexToConstantPoolCacheIndex(cpi, opcode); 646 index = getKlassRefIndexAt(index); 647 break; 648 } 649 default: 650 throw JVMCIError.shouldNotReachHere("Unexpected opcode " + opcode); 651 } 652 final Object type = compilerToVM().lookupKlassInPool(this, index); 653 return getJavaType(type); 654 } 655 656 @Override 657 public JavaField lookupField(int cpi, ResolvedJavaMethod method, int opcode) { 658 final int index = rawIndexToConstantPoolCacheIndex(cpi, opcode); 659 final int nameAndTypeIndex = getNameAndTypeRefIndexAt(index); 660 final int typeIndex = getSignatureRefIndexAt(nameAndTypeIndex); 661 String typeName = lookupUtf8(typeIndex); 662 JavaType type = runtime().lookupType(typeName, getHolder(), false); 663 664 final int holderIndex = getKlassRefIndexAt(index); 665 JavaType holder = lookupType(holderIndex, opcode); 666 667 if (holder instanceof HotSpotResolvedObjectTypeImpl) { 668 int[] info = new int[3]; 669 HotSpotResolvedObjectTypeImpl resolvedHolder; 670 try { 671 resolvedHolder = compilerToVM().resolveFieldInPool(this, index, (HotSpotResolvedJavaMethodImpl) method, (byte) opcode, info); 672 } catch (Throwable t) { 673 /* 674 * If there was an exception resolving the field we give up and return an unresolved 675 * field. 676 */ 677 return new UnresolvedJavaField(holder, lookupUtf8(getNameRefIndexAt(nameAndTypeIndex)), type); 678 } 679 final int flags = info[0]; 680 final int offset = info[1]; 681 final int fieldIndex = info[2]; 682 HotSpotResolvedJavaField result = resolvedHolder.createField(type, offset, flags, fieldIndex); 683 return result; 684 } else { 685 return new UnresolvedJavaField(holder, lookupUtf8(getNameRefIndexAt(nameAndTypeIndex)), type); 686 } 687 } 688 689 /** 690 * Converts a raw index from the bytecodes to a constant pool index (not a cache index). 691 * 692 * @param rawIndex index from the bytecode 693 * 694 * @param opcode bytecode to convert the index for 695 * 696 * @return constant pool index 697 */ 698 public int rawIndexToConstantPoolIndex(int rawIndex, int opcode) { 699 int index; 700 if (isInvokedynamicIndex(rawIndex)) { 701 assert opcode == Bytecodes.INVOKEDYNAMIC; 702 index = decodeInvokedynamicIndex(rawIndex) + config().constantPoolCpCacheIndexTag; 703 } else { 704 assert opcode != Bytecodes.INVOKEDYNAMIC; 705 index = rawIndexToConstantPoolCacheIndex(rawIndex, opcode); 706 } 707 return compilerToVM().constantPoolRemapInstructionOperandFromCache(this, index); 708 } 709 710 @Override 711 public void loadReferencedType(int cpi, int opcode) { 712 loadReferencedType(cpi, opcode, true /* initialize */); 713 } 714 715 @SuppressWarnings("fallthrough") 716 public void loadReferencedType(int cpi, int opcode, boolean initialize) { 717 int index; 718 switch (opcode) { 719 case Bytecodes.CHECKCAST: 720 case Bytecodes.INSTANCEOF: 721 case Bytecodes.NEW: 722 case Bytecodes.ANEWARRAY: 723 case Bytecodes.MULTIANEWARRAY: 724 case Bytecodes.LDC: 725 case Bytecodes.LDC_W: 726 case Bytecodes.LDC2_W: 727 index = cpi; 728 break; 729 case Bytecodes.INVOKEDYNAMIC: { 730 // invokedynamic instructions point to a constant pool cache entry. 731 index = decodeConstantPoolCacheIndex(cpi) + config().constantPoolCpCacheIndexTag; 732 index = compilerToVM().constantPoolRemapInstructionOperandFromCache(this, index); 733 break; 734 } 735 case Bytecodes.GETSTATIC: 736 case Bytecodes.PUTSTATIC: 737 case Bytecodes.GETFIELD: 738 case Bytecodes.PUTFIELD: 739 case Bytecodes.INVOKEVIRTUAL: 740 case Bytecodes.INVOKESPECIAL: 741 case Bytecodes.INVOKESTATIC: 742 case Bytecodes.INVOKEINTERFACE: { 743 // invoke and field instructions point to a constant pool cache entry. 744 index = rawIndexToConstantPoolCacheIndex(cpi, opcode); 745 index = compilerToVM().constantPoolRemapInstructionOperandFromCache(this, index); 746 break; 747 } 748 default: 749 throw JVMCIError.shouldNotReachHere("Unexpected opcode " + opcode); 750 } 751 752 final JvmConstant tag = getTagAt(index); 753 if (tag == null) { 754 assert getTagAt(index - 1) == constants.jvmDouble || getTagAt(index - 1) == constants.jvmLong; 755 return; 756 } 757 switch (tag.name) { 758 case "Methodref": 759 case "Fieldref": 760 case "InterfaceMethodref": 761 index = getUncachedKlassRefIndexAt(index); 762 // Read the tag only once because it could change between multiple reads. 763 final JvmConstant klassTag = getTagAt(index); 764 assert klassTag == constants.jvmClass || klassTag == constants.jvmUnresolvedClass || klassTag == constants.jvmUnresolvedClassInError : klassTag; 765 // fall through 766 case "Class": 767 case "UnresolvedClass": 768 case "UnresolvedClassInError": 769 final HotSpotResolvedObjectTypeImpl type = compilerToVM().resolveTypeInPool(this, index); 770 if (initialize && !type.isPrimitive() && !type.isArray()) { 771 type.ensureInitialized(); 772 } 773 if (tag == constants.jvmMethodref) { 774 if (Bytecodes.isInvokeHandleAlias(opcode) && isSignaturePolymorphicHolder(type)) { 775 final int methodRefCacheIndex = rawIndexToConstantPoolCacheIndex(cpi, opcode); 776 assert checkTag(compilerToVM().constantPoolRemapInstructionOperandFromCache(this, methodRefCacheIndex), constants.jvmMethodref); 777 compilerToVM().resolveInvokeHandleInPool(this, methodRefCacheIndex); 778 } 779 } 780 781 break; 782 case "InvokeDynamic": 783 if (isInvokedynamicIndex(cpi)) { 784 compilerToVM().resolveInvokeDynamicInPool(this, cpi); 785 } 786 break; 787 default: 788 // nothing 789 break; 790 } 791 792 } 793 794 // Lazily initialized. 795 private static String[] signaturePolymorphicHolders; 796 797 /** 798 * Determines if {@code type} contains signature polymorphic methods. 799 */ 800 @SuppressFBWarnings(value = "LI_LAZY_INIT_STATIC", justification = "signaturePolymorphicHolders is a cache, not a singleton that must be constructed exactly once" + 801 "and compiler re-ordering is not an issue due to the VM call") 802 static boolean isSignaturePolymorphicHolder(final ResolvedJavaType type) { 803 String name = type.getName(); 804 if (signaturePolymorphicHolders == null) { 805 signaturePolymorphicHolders = compilerToVM().getSignaturePolymorphicHolders(); 806 } 807 for (String holder : signaturePolymorphicHolders) { 808 if (name.equals(holder)) { 809 return true; 810 } 811 } 812 return false; 813 } 814 815 /** 816 * Check for a resolved dynamic adapter method at the specified index, resulting from either a 817 * resolved invokedynamic or invokevirtual on a signature polymorphic MethodHandle method 818 * (HotSpot invokehandle). 819 * 820 * @param cpi the constant pool index 821 * @param opcode the opcode of the instruction for which the lookup is being performed 822 * @return {@code true} if a signature polymorphic method reference was found, otherwise 823 * {@code false} 824 */ 825 public boolean isResolvedDynamicInvoke(int cpi, int opcode) { 826 if (Bytecodes.isInvokeHandleAlias(opcode)) { 827 final int methodRefCacheIndex = rawIndexToConstantPoolCacheIndex(cpi, opcode); 828 assert checkTag(compilerToVM().constantPoolRemapInstructionOperandFromCache(this, methodRefCacheIndex), constants.jvmMethodref); 829 int op = compilerToVM().isResolvedInvokeHandleInPool(this, methodRefCacheIndex); 830 return op == opcode; 831 } 832 return false; 833 } 834 835 public String getSourceFileName() { 836 final int sourceFileNameIndex = UNSAFE.getChar(getMetaspaceConstantPool() + config().constantPoolSourceFileNameIndexOffset); 837 if (sourceFileNameIndex == 0) { 838 return null; 839 } 840 return lookupUtf8(sourceFileNameIndex); 841 } 842 843 @Override 844 public String toString() { 845 HotSpotResolvedObjectType holder = getHolder(); 846 return "HotSpotConstantPool<" + holder.toJavaName() + ">"; 847 } 848 } 849